https://github.com/mitchellh/caststructure
A Go library that provides functions for downcasting types, composing values dynamically, and more.
https://github.com/mitchellh/caststructure
Last synced: 2 months ago
JSON representation
A Go library that provides functions for downcasting types, composing values dynamically, and more.
- Host: GitHub
- URL: https://github.com/mitchellh/caststructure
- Owner: mitchellh
- License: mit
- Created: 2020-04-29T22:49:14.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2020-05-01T04:23:12.000Z (about 5 years ago)
- Last Synced: 2025-04-10T05:59:25.723Z (3 months ago)
- Language: Go
- Homepage:
- Size: 14.6 KB
- Stars: 33
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
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 [](https://godoc.org/github.com/mitchellh/caststructure)
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](http://godoc.org/github.com/mitchellh/caststructure).
A quick code example is shown below that shows **downcasting**:
```go
// 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**:
```go
// 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](https://play.golang.org/p/It0NHvZt_-w). 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](https://play.golang.org/p/Sgn7MhsyrXt).
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.