caststructure

package module
v0.0.0-...-813ac3a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2020 License: MIT Imports: 2 Imported by: 0

README

⛔️ THIS DOESN'T WORK ⛔️

The functionality provided by this library unfortunately doesn't work due to limitations of the Go reflect package and runtime. I believe if these issues are resolved, the code here should work as-is and tests should begin passing.

The Go issues related to this are rooted here: https://github.com/golang/go/issues/38783

caststructure Godoc

caststructure is a Go library that provides functions for downcasting types, composing values dynamically, and more. See the examples below for more details.

Installation

Standard go get:

$ go get github.com/mitchellh/caststructure

Usage & Example

For usage and examples see the Godoc.

A quick code example is shown below that shows downcasting:

// Three interface types.
type A interface { A() int }
type B interface { B() int }
type C interface { C() int }

// Impl implements A, B, AND C.
type Impl struct {}
func (Impl) A() int { return 42 }
func (Impl) B() int { return 42 }
func (Impl) C() int { return 42 }

// We have a value of type Impl, so it implements all interfaces.
var value Impl

// But we only want value to implement A and B, not C.
newValue := caststructure.Must(caststructure.Down(value, (*A)(nil), (*B)(nil)))
_, ok := newValue.(A) // ok == true
_, ok := newValue.(B) // ok == true
_, ok := newValue.(C) // ok == false

Here is an example that shows composing:

// Three interface types.
type A interface { A() int }
type B interface { B() int }
type C interface { C() int }

// Implementation for A and B, respectively
type ImplA struct {}
func (ImplA) A() int { return 42 }

type ImplB struct {}
func (Impl) B() int { return 42 }

// We have a value that implements A and B, separately.
var valueA implA
var valueB implB

// But we want a value that implements BOTH A and B.
newValue := caststructure.Must(caststructure.Compose(valueA, (*A)(nil), valueB, (*B)(nil)))
_, ok := newValue.(A) // ok == true
_, ok := newValue.(B) // ok == true

But... Why?

In general, what this library achieves can be done manually through explicit type declarations. For example, composing A and B can be done explicitly like this. But in cases where the set of interfaces is large and the combinations dynamic, creating explicit types becomes a burden.

Some Go code allows optionally implementing interfaces to change behavior. For example, code might check if io.Closer is implemented and call it. If it is not implemented, it isn't an error, it just isn't called. Taking this further, some Go code has numerous opt-in interfaces to change behavior. This library was born out of the need to work with such APIs.

For downcasing, you might get a value that implements interfaces A, B, C and you want to return a value that only implements A and B. If this is the only scenario, you can manually create a new interface type. But if the list of interfaces you want to implement is dynamic, you would have to declare all combinations of the interface. This library does this dynamically at runtime, without panics.

For composing, you may have two separate values that implement two separate interfaces A and B respectively. For example, you may have an io.Reader and an io.Writer but you want an io.ReadWriter using the two together. This library can construct that ReadWriter for you.

Documentation

Overview

Package caststructure can downcast a value to a subset of the interfaces that it implements. This is useful in situations where the set of interfaces you want a type to implement is dynamic. In cases where the set is small or fixed, it is likely a better idea to define a new type instead.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compose

func Compose(pairs ...interface{}) (interface{}, error)

Compose composes multiple types into a single type. For example if you have a value that implements A and another that implements B, this can compose those two values into a single value that implements both A and B.

The arguments to this must be a list of pairs in (value, type) order. For example:

Compose(a, (*A)(nil), b, (*B)(nil))

func Down

func Down(from interface{}, to ...interface{}) (interface{}, error)

Down downcasts the value "from" to a type that implements the list of interfaces "to". The "from" value must already implement these interfaces. This is typically used to downcast a value that implements other interfaces to one that only implements the given list.

An error will be returned if from doesn't implement any one of the to values, or creating the structure fails (due to overlapping interface implements, unexported types being used, etc.).

func Must

func Must(v interface{}, err error) interface{}

Must is a helper that wraps a call to a function returning (interface{}, error) and panics if the error is non-nil. This can be used around Interface to force a successful return value or panic.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL