I have read several examples/questions about reflection in Go, but I'm still unable to understand what I'm supposed to do with my list of interfaces.
Below is a stripped down version of the real use case.
I have several types complying with a given interface:
type Foo interface {
Value() int
}
type bar struct {
value int
}
func (b bar) Value() int {
return b.value
}
type baz struct{}
func (b baz) Value() int {
return 42
}
I have a list of such guys
type Foos []Foo
var foos = Foos{
bar{},
baz{},
}
and I would like to traverse this list by changing the value of the members that have a value field.
for k := range foos {
change(&foos[k])
}
But I'm unable to find the right path
func change(g *Foo) {
t := reflect.TypeOf(g).Elem()
fmt.Printf("t: Kind %v, %#v\n", t.Kind(), t)
v := reflect.ValueOf(g).Elem()
fmt.Printf("v: Kind %v, %#v, %v\n", v.Kind(), v, v.CanAddr())
if f, ok := t.FieldByName("value"); ok {
fmt.Printf("f: %#v, OK: %v\n", f, ok)
vf := v.FieldByName("value")
fmt.Printf("vf: %#v: %v\n", vf, vf.CanAddr())
vf.SetInt(51)
}
}
As you can see, I'm not sure how to glue together the TypeOf and ValueOf bits...
The full example is on Go Playground.
There are a couple of issues here. First, it's not possible to set an unexported field. Here's a change to make the field exported:
type Foo interface {
// Rename Value to GetValue to avoid clash with Value field in bar
GetValue() int
}
type bar struct {
// export the field by capitalizing the name
Value int
}
func (b bar) GetValue() int {
return b.Value
}
type baz struct{}
func (b baz) GetValue() int {
return 42
}
The next issue is a bar interface value is not addressable. To fix this, use a *bar in the slice instead instead of a bar:
func (b *bar) GetValue() int {
return b.Value
}
...
var foos = Foos{
&bar{},
baz{},
}
With these changes, we can write the function to set the value:
func change(g Foo) {
v := reflect.ValueOf(g)
// Return if not a pointer to a struct.
if v.Kind() != reflect.Ptr {
return
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return
}
// Set the field Value if found.
v = v.FieldByName("Value")
if !v.IsValid() {
return
}
v.SetInt(31)
}
Run it on the playground
The above answers the question, but it may not be the best solution to the actual problem. A better solution may be to define a setter interface:
type ValueSetter interface {
SetValue(i int)
}
func (b *bar) Value() int {
return b.value
}
func (b *bar) SetValue(i int) {
b.value = i
}
func change(g Foo) {
if vs, ok := g.(ValueSetter); ok {
vs.SetValue(31)
}
}
Run it on the playground
Please don't use your current approach. It has several drawbacks.
It's confusing (as you've discovered)
It's slow. Reflection is always slow.
It's inflexible. Your loop, not the type itself, must understand the capabilities of each type implementation.
Instead, just expand your interface to include a setter method--possibly an optional setter method. Then you can loop through the items and set the value for those that support it. Example:
// FooSetter is an optional interface which allows a Foo to set its value.
type FooSetter interface {
SetValue(int)
}
// SetValue implements the optional FooSetter interface for type bar.
func (b *bar) SetValue(v int) {
b.value = v
}
Then make your loop look like this:
for _, v := range foos {
if setter, ok := v.(FooSetter); ok {
setter.SetValue(51)
}
}
Now when you (or a third party user of your library) adds a type Baz that satisfies the FooSetter interface, you don't have to modify your loop at all.
Related
TLDR; I need to use pointers to interface e.g. *Comparable as an internal Data's object in my Node as a part of Tree. Data should conform to pointer to Comparable interface that has only one method Less which compares two objects of Comparable interface type.
If I am using just Comparable as type for Data in Node, without pointer, everything works fine. However after I switch to *Comparable compiler gives strange errors and code won't compile
Code with Comparable:
package main
type Comparable interface {
Less(than Comparable) bool
}
type Node struct {
Data Comparable
}
func NewNode(data Comparable) *Node {
return &Node{Data: data} }
type Tree struct {
root *Node
}
func NewTree() *Tree {
return &Tree{}
}
func (t *Tree) insert(data Comparable) {
if t.root == nil || t.root.Data.Less(data) {
t.root = NewNode(data)
}
}
type Row struct {
Row []string
}
func NewRow(row[] string) *Row {
return &Row{Row: row}
}
func (r Row) Less(other Comparable) bool {
return r.Row[0] < other.(Row).Row[0]
}
func main() {
t := NewTree()
t.insert(*NewRow([]string{"123"}))
fmt.Printf("%v\n", t.root.Data.(Row).Row)
}
tests:
package main
import (
"reflect"
"testing"
)
func TestInsert(t *testing.T) {
d := []string{"42"}
tree := NewTree()
tree.insert(*NewRow(d))
if !reflect.DeepEqual(tree.root.Data.(Row).Row, d) {
t.Error("returned elements are not matching")
}
}
func TestInsert2x(t *testing.T) {
d1 := []string{"42"}
d2 := []string{"99"}
tree := NewTree()
tree.insert(*NewRow(d1))
tree.insert(*NewRow(d2))
if !reflect.DeepEqual(tree.root.Data.(Row).Row, d2) {
t.Error("returned elements are not matching")
}
}
However when I convert Comparable to *Comparable, everything breaks and the root cause is something like *Row is not equal to *Comparable compiler error:
for line return r.Row[0] < other.(*Row).Row[0]
Invalid type assertion: other.(*Row) (non-interface type *Comparable on left)
and for line if t.root == nil || t.root.Data.Less(data) {
Unresolved reference 'Less'
package main
type Comparable interface {
Less(than *Comparable) bool
}
type Node struct {
Data *Comparable
}
func NewNode(data *Comparable) *Node {
return &Node{Data: data}
}
type Tree struct {
root *Node
}
func NewTree() *Tree {
return &Tree{}
}
func (t *Tree) insert(data *Comparable) {
if t.root == nil || t.root.Data.Less(data) {
t.root = NewNode(data)
}
}
type Row struct {
Row []string
}
func NewRow(row[] string) *Row {
return &Row{Row: row}
}
func (r *Row) Less(other *Comparable) bool {
return r.Row[0] < other.(*Row).Row[0]
}
func main() {
t := NewTree()
t.insert(NewRow([]string{"123"}))
fmt.Printf("%v\n", t.root.Data.(*Row).Row)
}
tests:
package main
import (
"reflect"
"testing"
)
func TestInsert(t *testing.T) {
d := []string{"42"}
tree := NewTree()
tree.insert(NewRow(d))
if !reflect.DeepEqual(tree.root.Data.(*Row).Row, d) {
t.Error("returned elements are not matching")
}
}
func TestInsert2x(t *testing.T) {
d1 := []string{"42"}
d2 := []string{"99"}
tree := NewTree()
tree.insert(NewRow(d1))
tree.insert(NewRow(d2))
if !reflect.DeepEqual(tree.root.Data.(*Row).Row, d2) {
t.Error("returned elements are not matching")
}
}
The question is how to use *Comparable as type of Data in Node so that code above compiles. I tried a couple ugly options with interface{} type for Data and explicit casts everywhere. This approach I didn't like as it is very unsafe.
You can check all code parts in my github repo
Interfaces can accept both structs and pointers to structs.
You can pass in a pointer to Row (*Row) to Tree.insert(data Comparable), by combining your 1st Tree.insert(data Comparable) function definition with your 2nd main() function calls.
Here's a full running example, also on Go Playground: https://play.golang.org/p/Gh_RT3R-Fy0 .
package main
import (
"fmt"
)
type Comparable interface {
Less(than Comparable) bool
}
type Node struct {
Data Comparable
}
func NewNode(data Comparable) *Node {
return &Node{Data: data}
}
type Tree struct {
root *Node
}
func NewTree() *Tree {
return &Tree{}
}
func (t *Tree) insert(data Comparable) {
if t.root == nil || t.root.Data.Less(data) {
t.root = NewNode(data)
}
}
type Row struct {
Row []string
}
func NewRow(row []string) *Row {
return &Row{Row: row}
}
func (r Row) Less(other Comparable) bool {
return r.Row[0] < other.(*Row).Row[0]
}
func main() {
t := NewTree()
t.insert(NewRow([]string{"123"}))
fmt.Printf("%v\n", t.root.Data.(*Row).Row)
}
That being said, this is brittle code since the Row.Less function accesses the underlying type of Comparable and assumes the array has at a 0 index value (length > 0).
func (r Row) Less(other Comparable) bool {
return r.Row[0] < other.(*Row).Row[0]
}
It's much better to remove any dependency on the underlying type of Comparable when interface functions are called. You can do this augmenting the Comparable interface and Row.Less definition as follows. In this approach, there's no need to cast in the Row struct definition.
On Go Playground: https://play.golang.org/p/8-71-pEn-zK
type Comparable interface {
Less(than Comparable) bool
CompareValue() string
}
func (r Row) CompareValue() string {
if len(r.Row) == 0 {
return ""
}
return r.Row[0]
}
func (r Row) Less(other Comparable) bool {
return r.CompareValue() < other.CompareValue()
}
For more information on pointer to interfaces, see the Go FAQ on using pointers to interfaces:
https://golang.org/doc/faq#pointer_to_interface
When should I use a pointer to an interface?
Almost never. Pointers to interface values arise only in rare, tricky situations involving disguising an interface value's type for delayed evaluation.
It is a common mistake to pass a pointer to an interface value to a function expecting an interface. The compiler will complain about this error but the situation can still be confusing, because sometimes a pointer is necessary to satisfy an interface. The insight is that although a pointer to a concrete type can satisfy an interface, with one exception a pointer to an interface can never satisfy an interface.
[...]
The one exception is that any value, even a pointer to an interface, can be assigned to a variable of empty interface type (interface{}). Even so, it's almost certainly a mistake if the value is a pointer to an interface; the result can be confusing.
Could someone please explain (or if it's a long thing to explain at least point me to some documentation) why this code is behaving like it does. It's a bit lengthy but I couldn't figure out a good way of shortening it without losing too much info.
What confuses me is that I need to have the method "Find" on each type of struct for it to be recognized as the type it is. With Find on only the baseTypeImp is it printing that each is baseTypeImp, if I have it on baseTypeImp and advancedBaseTypeImp are those two identified correctly, but not the last type.
PlaygroundLink
My Code
package main
import (
"fmt"
"reflect"
)
type BaseType interface {
Name() string
Find(string) BaseType
Children() []BaseType
Options()
}
type baseTypeImp struct {
name string
children []BaseType
}
func (b baseTypeImp) Options() {
fmt.Println("Not implemented")
}
func (b baseTypeImp) Find(name string) BaseType {
if b.name == name {
return b
}
for _, c := range b.children {
if m := c.Find(name); m != nil {
return m
}
}
return nil
}
func (b baseTypeImp) Name() string {
return b.name
}
func (b baseTypeImp) Children() []BaseType {
return b.children
}
type AdvancedBaseType interface {
Value()
}
type advancedBaseTypeImp struct {
baseTypeImp
}
func (a advancedBaseTypeImp) Options() {
fmt.Println("Is implemented")
}
func (a advancedBaseTypeImp) Value() {
fmt.Println("Value called")
}
func (a advancedBaseTypeImp) Find(name string) BaseType {
if a.name == name {
return a
}
for _, c := range a.children {
if m := c.Find(name); m != nil {
return m
}
}
return nil
}
type reallyAdvancedBaseTypeImp advancedBaseTypeImp
func newThingy(name, variant string, children []BaseType) BaseType {
base := baseTypeImp{name: name, children: children}
switch variant {
case "advanced":
return advancedBaseTypeImp{baseTypeImp: base}
case "reallyAdvanced":
return reallyAdvancedBaseTypeImp{baseTypeImp: base}
}
return base
}
func whatType(b BaseType) {
if b == nil {
return
}
fooType := reflect.TypeOf(b)
fmt.Println(b.Name(), " is type ", fooType.Name())
b.Options()
}
func main() {
advanced := make([]BaseType, 0, 5)
for i := 0; i < 5; i++ {
advanced = append(advanced, newThingy(fmt.Sprintf("Advanced %d", i), "advanced", nil))
}
reallyAdvanced := make([]BaseType, 0, 2)
for i := 0; i < 2; i++ {
reallyAdvanced = append(reallyAdvanced, newThingy(fmt.Sprintf("ReallyAdvanced %d", i), "reallyAdvanced", advanced[i:i+3]))
}
basic := newThingy("Basic parent", "basic", reallyAdvanced)
whatType(basic.Find("Basic parent"))
for i := 0; i < 2; i++ {
whatType(basic.Find(fmt.Sprintf("Advanced %d", i)))
whatType(basic.Find(fmt.Sprintf("ReallyAdvanced %d", i)))
}
}
The output now is:
Basic parent is type baseTypeImp
Not implemented
Advanced 0 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 0 is type baseTypeImp
Not implemented
Advanced 1 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 1 is type baseTypeImp
Not implemented
What I'd like to have is:
Basic parent is type baseTypeImp
Not implemented
Advanced 0 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 0 is type reallyAdvancedBaseTypeImp
Is implemented
Advanced 1 is type advancedBaseTypeImp
Is implemented
ReallyAdvanced 1 is type reallyAdvancedBaseTypeImp
Is implemented
Is there a way to get this working without having to implement Find on each level? It kind of defeats the purpose of having the common methods in the top layer struct. And of course, if possible explain why it's behaving the way it does.
When you embed a struct into another one, the outer struct gets the methods of the embedded one.
type inner struct {
}
func (i inner) f() {}
type outer struct {
inner
}
...
x:=outer{}
x.f()
You can think of this as syntactic sugar for:
type outer2 struct {
i inner
}
y.i.f()
When you embed inner without a field name, you simply drop the i in the call. You can still call x.inner.f() in the first example.
When you redefine a type, it does not get the methods defined for its base type.
type newtype inner
newtype does not have f() defined. However, if inner also embeds other structs (like you do), then those are still embedded in the new type, so those function are defined:
type deepest struct {}
func (deepest) deep() {}
type inner struct{}
func (inner) in() {}
type outer inner
Above, the type outer does not have the function in, but it has deep.
So when you call reallyAdvancedBaseTypeImp.Find(), what you're really doing is reallyAdvancedBaseTypeImp.baseTypeImp.Find(), which works on that portion of the struct. That's why you're getting the types you get.
You're trying to emulate method overriding. You can't really do that. Formulate your problem in a different way.
Should I check for nil values in the constructor and then set an unexported struct field, or make the default struct value useful by checking for nil at method level?
type Foo struct{}
func (f *Foo) Baz() {}
var DefaultFoo = new(Foo)
type Bar struct {
Foo *Foo
}
func (b *Bar) Baz() {
if b.Foo == nil {
DefaultFoo.Baz()
} else {
b.Foo.Baz()
}
}
or
type Foo struct{}
func (f *Foo) Baz() {}
var DefaultFoo = new(Foo)
type Bar struct {
foo *Foo
}
func NewBar(foo *Foo) *Bar {
if foo == nil {
foo = DefaultFoo
}
return &Bar{foo}
}
func (b *Bar) Baz() {
b.foo.Baz()
}
I don't think there is a "right" answer for this.
Having said this, the approach usually seen in the Go base libraries is letting the objects be created without any constructor, with nil or zero values in its fields, and then make the methods have logic to use or return useful defaults.
Take a look at the http.Client implementation for example:
https://github.com/golang/go/blob/master/src/net/http/client.go
It will basically let you create a new client by just doing:
client := &http.Client{}
You can then populate the fields of the object if you want to override defaults, otherwise it'll check for nil in different methods to provide default behaviour, for example:
https://github.com/golang/go/blob/master/src/net/http/client.go#L195
func (c *Client) transport() RoundTripper {
if c.Transport != nil {
return c.Transport
}
return DefaultTransport
}
My use case is, I need to have several structs in Go, who will have methods of same signatures and not necessarily have to have all the methods. The following code describes the requirements and also represents my current solution.
type calc struct {
fn func(a, b int) int
gn func(a string) bool
name string
}
func add(a, b int) int {
return a + b
}
func bar(foo string) bool {
// do something
}
func sub(a, b int) int {
return a - b
}
func main() {
for c := range []calc{{
fn: add,
gn: bar,
name: "addition",
}, {
fn: sub,
name: "subtraction",
}} {
fmt.Printf("%s(10, 15) returned: %d\n", c.name, c.fn(10, 15))
if c.gn != nil {
c.gn(c.name)
}
}
}
My question is how to improve this code? What's the best way to achieve this in Go? Can I achieve a better solution using interface?
Use interfaces.
type Op interface {
Name() string
Do(a, b int) int
}
type Add struct{}
func (Add) Name() string { return "add" }
func (Add) Do(a, b int) int { return a + b }
type Sub struct{}
func (Sub) Name() string { return "sub" }
func (Sub) Do(a, b int) int { return a - b }
Playground: http://play.golang.org/p/LjJt6D0hNF.
EDIT: Since you've edited your question, here is an example of how you could use asserting and interface to a broader interface for your task:
type RevOp interface {
Op
ReverseDo(a, b int) int
}
// ...
func (Add) ReverseDo(a, b int) int { return a - b }
// ...
fmt.Printf("%s(10, 15) returned: %d\n", op.Name(), op.Do(10, 15))
if op, ok := op.(RevOp); ok {
fmt.Printf("reverse of %s(10, 15) returned: %d\n", op.Name(), op.ReverseDo(10, 15))
}
Playground: http://play.golang.org/p/MQ6LlPDcEi.
I've discussed with some people in person and apparently my solution was correct. While it can be rewritten using interface, that's not necessarily an improvement.
Say I have functions:
func ToModelList(cats *[]*Cat) *[]*CatModel {
list := *cats
newModelList := []*CatModel{}
for i := range list {
obj := obj[i]
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}
func ToModelList(dogs *[]*Dog) *[]*DogModel {
list := *dogs
newModelList := []*DogModel{}
for i := range list {
obj := obj[i]
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}
Is there a way to combine those two so I can do something like
func ToModelList(objs *[]*interface{}) *[]*interface{} {
list := *objs
// figure out what type struct type objs/list are
newModelList := []*interface{}
// type cast newModelList to the correct array struct type
for i := range list {
obj := obj[i]
// type cast obj based on objs's type
newModelList = append(newModelList, obj.ToModel())
}
return &newModelList
}
First, slices are already a reference, unless you need to change the slice itself, you do not need to pass it as a pointer.
Second, an interface{} can be regardless an object or a pointer to an object. You do not need to have *interface{}.
I am not sure what you are trying to achieve but you could do something like this:
package main
// Interface for Cat, Dog
type Object interface {
ToModel() Model
}
// Interface for CatModel, DogModel
type Model interface {
Name() string
}
type Cat struct {
name string
}
func (c *Cat) ToModel() Model {
return &CatModel{
cat: c,
}
}
type CatModel struct {
cat *Cat
}
func (c *CatModel) Name() string {
return c.cat.name
}
type Dog struct {
name string
}
func (d *Dog) ToModel() Model {
return &DogModel{
dog: d,
}
}
type DogModel struct {
dog *Dog
}
func (d *DogModel) Name() string {
return d.dog.name
}
func ToModelList(objs []Object) []Model {
newModelList := []Model{}
for _, obj := range objs {
newModelList = append(newModelList, obj.ToModel())
}
return newModelList
}
func main() {
cats := []Object{
&Cat{name: "felix"},
&Cat{name: "leo"},
&Dog{name: "octave"},
}
modelList := ToModelList(cats)
for _, model := range modelList {
println(model.Name())
}
}
You define interfaces for your Cat, Dogs etc and for your Model. Then you implement them as you want and it is pretty straight forward to do ToModelList().
you can make *CatModel and *DogModel both implement type PetModel {} interface, and just return []Pet in function signature.
func (cats []*Cat) []PetModel {
...
return []*CatModel {...}
}
func (dogs []*Dog) []PetModel {
...
return []*DogModel {...}
}
BTW: return a pointer of a slice in golang is useless.
If you strip away redundant assignments, and unnecessary pointers-to-slices, you'll find you have little code left, and duplicating it for each of your model types doesn't look so bad.
func CatsToCatModels(cats []*Cat) []*CatModel {
var result []*CatModel
for _, cat := range cats {
result = append(result, cat.ToModel())
}
return result
}
Unless this code is used in a lot of places I'd also consider just inlining it, since it's trivial code and only 4 lines when inlined.
Yes, you can replace all the types with interface{} and make the code generic, but I don't think it's a good tradeoff here.