Empty Interfaces in Golang - go

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

Related

How to create a copy of a struct only having interface it implements and it's value

Let's say I have this A struct that implements Setter interface:
type Setter interface {
Set(key string, value string)
}
type A struct {
m map[string]string
}
func (a *A) Set(key string, value string) {
a.m[key] = value
}
And I have one different struct that holds some implementation of Setter interface
type Holder struct {
val Setter
}
h := Holder{
val: &A{ map[string]string{} },
}
What i need is to get a copy of the h.val struct with all values saved.
I have already tried the following solution but it did not work, resulting with panic: assignment to entry in nil map
(We have defined the map when initiallizing h, so by running h.val.Set(k, v) we won't get any errors)
l := reflect.New(
reflect.ValueOf(h.val).Elem().Type(),
).Interface().(Setter)
l.Set("A", "B")
How can I create a copy of a struct without knowing which fields it consists of, only knowing the interface it implements and having it's value in a variable?
p.s. Adding Clone method to Setter interface is not a preferred solution
Adding Clone method to Setter interface is not a preferred solution
in all generality, since only the Setter implementation knows how it should be "cloned", there isn't much choice.
For example : should "cloning" an A struct create a new struct pointing at the same mapping ? or should it duplicate the mapping ?
If your intention is really to clone, you probably want the second, but you can see it will quickly fall outside the scope of a simple reflect operation.
If your code actually only deals with A structs, you may pass explicit A values. You will probably still need a .Clone() method or a Clone(a *A) function.
If your only issue is that a zero value for A is invalid, you can fix Set() :
func (a *A) Set(key string, value string) {
if a.m == nil {
a.m = make(map[string]string)
}
a.m[key] = value
}

How do you make a function accept multiple types?

I am having a function like this:
package main
import "flag"
import "fmt"
func print_out_type(x anything) string {
switch v := x.(type) {
case string:
return "A string"
case int32:
return "An Integer"
default:
return "A default"
}
}
func main() {
wordPtr := flag.String("argument1", "foo", "a String")
numPtr := flag.Int("argument2", 42, "an Integer")
flag.Parse()
fmt.Println("word: ", *wordPtr)
fmt.Println("number: ", *numPtr)
}
I am trying to return different types of strings based on the type. I am just stuck at the point of how do I write a function that accepts arguments of different types.
You can use interface types as arguments, in which case you can call the function with any type that implements the given interface. In Go types automatically implement any interfaces if they have the interface's methods. So if you want to accept all possible types, you can use empty interface (interface{}) since all types implement that. No other modification needs to be done to your function.
func print_out_type(x interface{}) string {
switch v := x.(type) {
case string:
return "A string"
case int32:
return "An Integer"
default:
return "A default"
}
}
You can also use the reflect package to study the type of an interface variable. For Example:
func print_out_type(x interface{}) string {
return reflect.TypeOf(x).String()
}
func main() {
fmt.Println(print_out_type(42))
fmt.Println(print_out_type("foo"))
}
Will print
int
string
Starting with Go 1.18. you can use generics to specify which types can be used in a function.
func print_out_type[T any](x T) string {
return fmt.Sprintf("%T", x)
}
https://go.dev/doc/tutorial/generics
First, if you are using a type assertion, you need to check that this operation is successful. eg: value, ok := temp.(int)
Second, you can use the interface{} type variable as a parameter to the function. In the Function, you can use type assertion to check the parameter's real type and print out.

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"`
}

Golang: Where is an Interface method called?

I don't understand at which point an Interface method is being called. I'm looking at the following example from the Go Tour:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
Problem:
I understand that the func (p Person) receives the String() method and that it returns the string I want to display. But the fmt.Println in the main() method has to call String() at some point, right?
I had a look at the source of fmt in godoc, but I still cannot figure it out!
Another example:
If I add my own interface, lets say Stringer2 with a method called String2() and then create a func (p Person) String2() {....}.
How does String() get executed by fmt.Println, but String2() not?
The value is passed to Println as an interface{}, and is checked if it satisfies the fmt.Stringer interface via a "type assertion" often in the form of a "type switch".
func IsStringer(i interface{}) {
switch s := i.(type) {
case fmt.Stringer:
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
default:
fmt.Println("not a stringer")
}
// OR for a single type
if s, ok := i.(fmt.Stringer); ok {
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
}
}
However, other methods may take precedence when printing from the fmt package. There are first checks for fmt.Formatter, fmt.GoStringer, error, and then finally fmt.Stringer.
The fmt package works with the interfaces it defines, in this case Stringer. It does not know of interfaces defined by you so it wouldn't know to call String2() even if you pass it a type that meets the Stringer2 interface.
Interfaces are a way to have common behavior between types. So if you create a function Foo(s Stringer2), Foo can simply call s.String2() confident that anything passed into it will have the function String2().
To go a bit deeper, fmt.Println takes interface{} types and then uses reflection to check if the given argument meets the Stringer interface to then call String().
Make sense?

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 .

Resources