Add struct or pointer to struct to slice - go

Say I have structs like so:
type Foo struct {
F string `zoom:"1"`
}
type Bar struct {
F string `zoom:"2"`
}
type Baz struct {
F string `zoom:"3"`
}
Say I wanted to create a func that can extract the f field from each struct, it might look like:
func extractField(s []struct{}){
for _, v := range s {
t := reflect.TypeOf(v{})
f, _ := t.FieldByName("F")
v, ok := f.Tag.Lookup("zoom")
}
}
is there a way to pass the structs to extractField? If I do this:
extractField([]struct{}{Foo, Bar, Baz})
I get this error:
Type Foo is not an expression
Type Bar is not an expression
Type Baz is not an expression
I just want to pass the 3 structs to the extractField func.

The only way I could figure out how to do this, is like so:
type Foo struct {
F string `zoom:"1"`
}
type Bar struct {
F string `zoom:"2"`
}
type Baz struct {
F string `zoom:"3"`
}
func extractField(s []interface{}){
for _, v := range s {
t := reflect.TypeOf(v)
f, _ := t.FieldByName("F")
v, ok := f.Tag.Lookup("zoom")
fmt.Println(v,ok)
}
}
func main(){
extractField([]interface{}{Foo{},Bar{},Baz{}}) // <<<< here
}
not sure if there is a way to pass a struct without "instantiating it" first.

The original code looks like it follows a JavaScript approach, where a function would mutate an object. Go is a little bit different, where it's more common to self-mutate.
For example:
type Generic struct {
field string
}
func (generic *Generic) Value () string {
return generic.field
}
someObject := &Generic{
field: "some value",
}
log.Print(someObject.Value()) // Outputs "some value"
If you're coming from the JavaScript world, think of structs a little bit like an object/class that can contain attributes and functions. Structs are merely a definition until an instance is instantiated. This differs from JavaScript where the definition of the object and the data are both defined at the same time.
As the other answer points out, an interface is another similar approach to dealing with this.
Clarification
In JavaScript terms, the OP is attempting to do something akin to:
class Foo {...}
class Bar {...}
class Baz {...}
extractField(Foo, Bar, Baz)
In JS-speak, this would pass a class definition to the extractField method. You would still have to instantiate an instance of a class if you want to manipulate/read from it, like:
extractField(new Foo(), new Bar(), new Baz())
This is basically what is being accomplished with
extractField([]interface{}{Foo{},Bar{},Baz{}})
I think the problem you're running into is the Foo/Bar/Baz structs are instantiated, but the nested F struct is not.

The overall problem seems like a much better match for an interface type.
type HasF interface {
GetF() string
}
It's easy enough to define these methods, e.g.
func (foo Foo) GetF() string { return foo.F }
Your method to iterate over them becomes almost trivial
func extractField(s []HasF) {
for _, v := range s {
fmt.Printf(v.GetF())
}
}
func main() {
extractField([]HasF{Foo{},Bar{},Baz{}})
}
https://play.golang.org/p/uw0T7TGVC0n has a complete version of this.

Related

Empty Interfaces in Golang

Edit: This is not the right way to use interfaces in Go. The purpose of this question is for me to understand how empty interfaces work in Go.
If all types in Go implement interface{} (empty interface), why can't I access the name field in the Cat and Dog structs? How can I get access to the name field of each struct through the function sayHi()?
package main
import (
"fmt"
)
func sayHi(i interface{}) {
fmt.Println(i, "says hello")
// Not understanding this error message
fmt.Println(i.name) // i.name undefined (type interface {} is interface with no methods)
}
type Dog struct{
name string
}
type Cat struct{
name string
}
func main() {
d := Dog{"Sparky"}
c := Cat{"Garfield"}
sayHi(d) // {Sparky} says hello
sayHi(c) // {Garfield} says hello
}
An interface{} is a method set, not a field set. A type implements an interface if it's methods include the methods of that interface. Since empty interface doesn't have any methods, all types implement it.
If you need to access a field, you have to get the original type:
name, ok:=i.(Dog).name
This will recover the name if i is a Dog.
Alternatively, implement a getName() function for both Dog and Cat, and then they will both implement the following interface:
type NamedType interface {
getName() string
}
Then you can rewrite your function as:
func sayHi(i NamedType) {
fmt.Println(i.getName())
}
You can't do that because interface values don't do that.
What interface values do—regardless of the interface type itself; it doesn't matter if the interface type is empty or not—is that they hold two things:
the concrete type of some value (or no type); and
the value of that concrete type (or no value).
So if some variable v or expression e has type I where I is an interface type, then you can, with some syntax, inspect either or both of these two "fields". They're not struct fields so you can't just use v.type, but you can do this:
switch v.(type) {
case int: // the value in v has type int
case *float64: // the value in v has type float64
// etc
}
The .(type) in a switch means let me look at the type field.
Getting the actual value is harder, because Go more or less requires that you check the type first. In your case, you know that i holds either a Dog or a Cat, so you can write:
var name string
switch i.(type) {
case Dog: name = i.(Dog).name
case Cat: name = i.(Cat).name
default: panic("whatever 'i' is, it is not a Dog or Cat")
}
fmt.Println(name)
This is pretty clumsy, and there are lots of ways to make it less clumsy, but that's always the first step: figure out what the type is.
Well, sometimes there's a step before the first step: figure out whether the variable has anything at all in it. You do this with:
if i == nil {
...
}
Note, however, that if i has some typed value in it, and the type can hold nil pointers, the value part of i can be nil and yet i == nil will be false. That's because i does have a type in it.
var i interface{}
var p *int
if i == nil {
fmt.Println("i is initially nil")
}
if p == nil {
fmt.Println("p is nil")
}
i = p
if i != nil {
fmt.Printf("i is now not nil, even though i.(*int) is %v\n", i.(*int))
}
(try this on the Go playground).
This usually isn't the right way to use interface
Most often—there are exceptions—we don't even try to look at the type of some interface. Instead, we define an interface that provides methods—functions we can call—that do something we need done. See Burak Serdar's answer in which the interface type has a getName method. Then, instead of trying to figure out which of some limited set of types someone gave us, we just say:
name := i.getName()
to invoke the getName method on the underlying concrete value. If i holds a Dog, that calls func (Dog) getName() string, which you'll need to define. If i holds a Cat, it calls func (Cat) getName() string. If you decide to add to your collection a type named Bird, you can define func (Bird) getName() string, and so on.
(Usually, the methods would be exported too: GetName, rather than getName.)
Like you say, interface{} is an empty interface. How can you assume that something "empty" has a name field in it (fmt.Println(i.name))? You can't. In fact, go doesn't support fields in interfaces, only methods.
What you can do (and there are, of course, many solutions), is to define an interface (let's call it Pet) which has a method returning the pet's name:
type Pet interface {
getName() string
}
Then you can receive this interface (its object) in the sayHi function and use it to print the pet's name:
func sayHi(i Pet) {
fmt.Println(i.getName())
}
Now, in order to be able to pass Dog or Cat to sayHi(), both of these structs have to implement the interface. So, define the getName() methods for them:
func (d Dog) getName() string {
return d.name
}
func (c Cat) getName() string {
return c.name
}
And that's it.
It can also be implemented using switch type as below-
package main
import (
"fmt"
)
func sayHi(i interface{}) {
fmt.Println(i, "says hello")
switch x := i.(type) {
case Dog:
fmt.Println(x.name)
case Cat:
fmt.Println(x.name)
}
}
type Dog struct {
name string
}
type Cat struct {
name string
}
func main() {
d := Dog{"Sparky"}
c := Cat{"Garfield"}
sayHi(d) // {Sparky} says hello
sayHi(c) // {Garfield} says hello
}
Playground link - https://go.dev/play/p/p4s3_jmmbGJ

How to set default values in Go structs

There are multiple answers/techniques to the below question:
How to set default values to golang structs?
How to initialize structs in golang
I have a couple of answers but further discussion is required.
One possible idea is to write separate constructor function
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
Force a method to get the struct (the constructor way).
From this post:
A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.
This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.
Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.
One problem with option 1 in answer from
Victor Zamanian is that if the type isn't exported then users of your package can't declare it as the type for function parameters etc. One way around this would be to export an interface instead of the struct e.g.
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
Which lets us declare function parameter types using the exported Candidate interface.
The only disadvantage I can see from this solution is that all our methods need to be declared in the interface definition, but you could argue that that is good practice anyway.
There is a way of doing this with tags, which
allows for multiple defaults.
Assume you have the following struct, with 2 default
tags default0 and default1.
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
Now it's possible to Set the defaults.
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
Here's the complete program in a playground.
If you're interested in a more complex example, say with
slices and maps, then, take a look at creasty/defaultse
From https://golang.org/doc/effective_go.html#composite_literals:
Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from package os.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
What about making something like this:
// Card is the structure we work with
type Card struct {
Html js.Value
DefaultText string `default:"html"` // this only works with strings
}
// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
c.Html = Document.Call("createElement", "div")
return c
}
Then call it as:
c := new(Card).Init()
I found this thread very helpful and educational. The other answers already provide good guidance, but I wanted to summarize my takeaways with an easy to reference (i.e. copy-paste) approach:
package main
import (
"fmt"
)
// Define an interface that is exported by your package.
type Foo interface {
GetValue() string // A function that'll return the value initialized with a default.
SetValue(v string) // A function that can update the default value.
}
// Define a struct type that is not exported by your package.
type foo struct {
value string
}
// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
return &foo{
value: "I am the DEFAULT value.",
}
}
// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
return f.value
}
// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
f.value = v
}
func main() {
f := NewFoo()
fmt.Printf("value: `%s`\n", f.GetValue())
f.SetValue("I am the UPDATED value.")
fmt.Printf("value: `%s`\n", f.GetValue())
}
One way to do that is:
// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}
So whenever you need a new variable of your custom defined type just call the NewA function also you can parameterise the function to optionally assign the values to the struct fields
func NewA() *A {
return &A{
Filed1: "",
Field2: make(map[string]interface{}),
}
}
for set default values in Go structs we use anonymous struct:
Person := struct {
name string
age int
city string
}{
name: "Peter",
age: 21,
city: "Noida",
}
fmt.Println(Person)
Structs
An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:
type Circle struct {
x float64
y float64
r float64
}
The type keyword introduces a new type. It's followed by the name of the type (Circle), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:
type Circle struct {
x, y, r float64
}
Initialization
We can create an instance of our new Circle type in a variety of ways:
var c Circle
Like with other data types, this will create a local Circle variable that is by default set to zero. For a struct zero means each of the fields is set to their corresponding zero value (0 for ints, 0.0 for floats, "" for strings, nil for pointers, …) We can also use the new function:
c := new(Circle)
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (*Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
Or we can leave off the field names if we know the order they were defined:
c := Circle{0, 0, 5}
type Config struct {
AWSRegion string `default:"us-west-2"`
}

Perform an action on a collection of items

In my actual code, I'm parsing an XML document using encoding/xml, and I basically have a bunch of nested structures of the following form — all of which may occur multiple times, except the top-level statements element:
statements
statement
opcode
args
pre
post
I'm fairly new to Go, and I'm clearly misunderstanding how interface{} (the empty interface) works:
.\stmtgen.go:58: cannot use print_name (type func(Statement)) as type func(interface {}) in argument to performAction
.\stmtgen.go:58: cannot use slist (type []Statement) as type []interface {} in argument to performAction
Relevant example code:
package main
import "fmt"
// Actually a structure in my code, but this suffices for demonstration.
type Opcode int
// A Statement has a Name and multiple Opcodes may use this Name.
type Statement struct {
Name string
Opcodes []Opcode
}
// Print the statement name.
func print_name(stmt Statement) {
fmt.Println(stmt.Name)
}
// Perform an action on each item of a collection.
func performAction(action func(interface{}), v []interface{}) {
for i := range v {
action(v[i])
}
}
func main() {
slist := make([]Statement, 3)
slist[0] = Statement{"Statement 1"}
slist[1] = Statement{"Statement 2"}
slist[2] = Statement{"Statement 3"}
//ERROR HERE
performAction(print_name, slist)
}
Must I create functions to print the values for every single type?
An empty interface{} can contain any value and passed around as the type interface{}. when you need the value from it, you can perform a type assertion like this:
var anyValue interface{}
anyValue = "hello"
strValue := anyValue.(string)
If anyValue is not of the type being asserted then it will cause a panic
the type assertion can also be used to return a bool if the interface is of that type with a multiple return
strValue, ok := anyValue.(string)
if ok {
//anyValue contains a string!
}
If you dont know the type of the interface, you can use a switch to determine it's type like this:
switch val := anyValue.(type) {
case string:
// anyValue contains a string
// and val is a string
break
case int:
// anyValue contains an int
// and val is and int
break
default:
//unhandled interface type
}
Hopefully this makes the empty interface{} type clearer.
interfaces{...} which have methods declared in them are different, they can not have members (like structs can), only methods, and their underlying type must implement all the methods declared in the interface. You could have an interface actionPerformer (interface names should have the suffix "er" as they are doing something)
type actionPerformer interface {
action(interface{})
}
A type that implements all the methods in an interface can be cast to that interface type, then if you call one of those methods on the interface, it will run the method on the underlying type.
For example, if the Statement struct implements the action(interface{}) method, the Statement struct can be cast to an actionPerformer type and if the action(interface{}) function is called on the actionPerformer, the action function on the Statement struct is run. So you could have multiple types that all have the action(interface{}) method and they can all be cast to an actionPerformer which you can call the action function on.
func (code Opcode) action(arg interface{}) {
fmt.Println(arg.(int) + int(code))
}
func (stmt Statement) action(arg interface{}) {
fmt.Println(arg.(string), stmt.Name)
}
stmt := Statement{"Statement 1", nil}
stmtActionPerformer := actionPerformer(stmt)
opcode := Opcode(5)
opcodeActionPerformer := actionPerformer(opcode)
stmtActionPerformer.action("hello") // will print "hello "+whatever the statements name is
opcodeActionPerformer.action(2) //will print be 7
Type assertions can still be used on these types of interface e.g.
stmt := stmtActionPerformer.(Statement)
fmt.Println(stmt.Name)
This is a contrived example, but with this in mind, you might want to write your code using interfaces like this.
Remember casting between interfaces is costly, so should be done sparingly, however they are a powerful tool when used correctly.
For your example, a simple printNames function would be much more efficient than all that interface casting (note that in golang, names should be in the CamelCase format, not using underscores)
func printNames(stmts []Statement) {
for _, stmt := range stmts {
fmt.Println(stmt.Name)
}
}
It might also be useful to have a type StatementList and add methods to it:
type StatementList []Statement
func (list StatementList) printNames() {
for _, stmt := range list {
fmt.Println(stmt.Name)
}
}
Getting the hang of this stuff make golang a lot more fun, hope this helps :)
You have to declare the parameters of performAction exactly same like the arguments type.
func performAction(action func(Statement), v []Statement) {
for i := range v {
action(v[i])
}
}
Or you could use interface{} on all parameters instead. Then cast it according to the needs.
func performAction(action interface{}, v interface{}) {
for _, each := range v.([]Statement) {
action.(func(Statement))(each)
}
}
data with type []Statement cannot be assigned to []interface{}
also for type func(Statement) cannot be assigned to func(interface{})
Use interface{}, then cast it to the original type.
this works for me:
package main
import (
"fmt"
)
// Actually a structure in my code, but this suffices for demonstration.
type Opcode int
// A Statement has a Name and multiple Opcodes may use this Name.
type Statement struct {
Name string
Opcodes []Opcode
}
// Print the statement name.
func print_name(stmt interface{}) {
if s, ok := stmt.(Statement); !ok {
panic("typ err")
} else {
fmt.Println(s.Name)
}
}
// Perform an action on each item of a collection.
func performAction(action func(interface{}), v []interface{}) {
for i := range v {
action(v[i])
}
}
func main() {
slist := make([]interface{}, 3)
slist[0] = Statement{"Statement 1", nil}
slist[1] = Statement{"Statement 2", nil}
slist[2] = Statement{"Statement 3", nil}
performAction(print_name, slist)
/*output:
Statement 1
Statement 2
Statement 3
*/
}

Golang methods with same name and arity, but different type

The following code works fine. Two methods operating on two different structs and printing a field of the struct:
type A struct {
Name string
}
type B struct {
Name string
}
func (a *A) Print() {
fmt.Println(a.Name)
}
func (b *B) Print() {
fmt.Println(b.Name)
}
func main() {
a := &A{"A"}
b := &B{"B"}
a.Print()
b.Print()
}
Shows the desired output in the console:
A
B
Now, if I change the method signature in the following way I get an compile error. I just move the receiver of the method to the arguments of the method:
func Print(a *A) {
fmt.Println(a.Name)
}
func Print(b *B) {
fmt.Println(b.Name)
}
func main() {
a := &A{"A"}
b := &B{"B"}
Print(a)
Print(b)
}
I can't even compile the program:
./test.go:22: Print redeclared in this block
previous declaration at ./test.go:18
./test.go:40: cannot use a (type *A) as type *B in function argument
Why is it that I can interchange struct types in the receiver, but not in the
arguments, when the methods have the same name and arity?
Because Go does not support overloading of user-defined functions on their argument types.
You can make functions with different names instead, or use methods if you want to "overload" on only one parameter (the receiver).
You can use type introspection. As a general rule, though, any use of the generic interface{} type should be avoided, unless you are writing a large generic framework.
That said, a couple of ways to skin the proverbial cat:
Both methods assume a Print() method is defined for both types (*A and *B)
Method 1:
func Print(any interface{}) {
switch v := any.(type) {
case *A:
v.Print()
case *B:
v.Print()
default:
fmt.Printf("Print() invoked with unsupported type: '%T' (expected *A or *B)\n", any)
return
}
}
Method 2:
type Printer interface {
Print()
}
func Print(any interface{}) {
// does the passed value honor the 'Printer' interface
if v, ok := any.(Printer); ok {
// yes - so Print()!
v.Print()
} else {
fmt.Printf("value of type %T passed has no Print() method.\n", any)
return
}
}
If it's undesirable to have a Print() method for each type, define targeted PrintA(*A) and PrintB(*B) functions and alter Method 1 like so:
case *A:
PrintA(v)
case *B:
PrintB(v)
Working playground example here.
You can not do function or method overloading in Go. You can have two methods with the same names in Go but the receiver of these methods must be of different types.
you can see more in this link .

Refactor function to make it reusable across types in Go

I have a function that initializes an array of structs from an array of an array of values. This is how I'm doing it currently:
type Loadable interface {
Load([]interface{})
}
type FooList struct {
Foos []*Foo
}
func (fl *FooList) Load(vals []interface{}) {
fl.Foos = make([]*Foo, len(vals))
for i, v := range vals {
foo := &Foo{}
foo.Load(v.([]interface{}))
fl.Foos[i] = foo
}
}
This works just fine, but now I also need to initialize BarLists and BazLists which contain Bars and Bazs. Instead of sprinkling the same snippet throughout my code which all look like this:
type BarList struct {
Bars []*Bar
}
func (fl *BarList) Load(vals []interface{}) {
fl.Bars = make([]*Bar, len(vals))
for i, v := range vals {
bar := &Bar{}
bar.Load(v.([]interface{}))
fl.Bars[i] = bar
}
}
What's the correct way to refactor this code to make it more DRY?
The code you show does not violate the DRY principle. The code implementing the Loader interface (I refuse to write the javaism you used) for type FooList and BarList shares only one line - the range statement. Otherwise they're type specific.
As Go has no generics, there's no direct way how to not write type specialized versions in a generic way (modulo poor choices like everything is an interface{} etc. and/or slowing down your code 10 times by using reflection.)
The simplest I can come up with using reflection would be something like this (not tested):
import "reflect"
// example_of_type should be an instance of the type, e.g. Foo{}
// returns slice of pointers, e.g. []*Foo
func Load(vals []interface{}, example_of_type interface()) interface{} {
type := reflect.TypeOf(example_of_type)
list := reflect.MakeSlice(type.PtrOf().SliceOf(), len(vals), len(vals))
for i, v := range vals {
bar := reflect.New(type)
bar.Interface().(Loadable).Load(v.([]interface{}))
list.Index(i).Set(bar)
}
return list.Interface()
}
You would use it like:
fl.Foos = Load(vals, Foo{}).([]*Foo)
fl.Bars = Load(vals, Bar{}).([]*Bar)

Resources