go generics: how to declare a type parameter compatible with another type parameter - go

I'm looking for a way to declare type compatibility between type parameters in Go generics constraints.
More specifically, I need to say some type T is compatible with another type U. For instance, T is a pointer to a struct that implements the interface U.
Below is a concrete example of what I want to accomplish:
NOTE: Please, do not answer with alternative ways to implement "array prepend". I've only used it as a concrete application of the problem I'm looking to solve. Focusing on the specific example digresses the conversation.
func Prepend[T any](array []T, values ...T) []T {
if len(values) < 1 { return array }
result := make([]T, len(values) + len(array))
copy(result, values)
copy(result[len(values):], array)
return result
}
The above function can be called to append elements of a given type T to an array of the same type, so the code below works just fine:
type Foo struct{ x int }
func (self *Foo) String() string { return fmt.Sprintf("foo#%d", self.x) }
func grow(array []*Foo) []*Foo {
return Prepend(array, &Foo{x: len(array)})
}
If the array type is different than the elements being added (say, an interface implemented by the elements' type), the code fails to compile (as expected) with type *Foo of &Foo{…} does not match inferred type Base for T:
type Base interface { fmt.Stringer }
type Foo struct{ x int }
func (self *Foo) String() string { return fmt.Sprintf("foo#%d", self.x) }
func grow(array []Base) []Base {
return Prepend(array, &Foo{x: len(array)})
}
The intuitive solution to that is to change the type parameters for Prepend so that array and values have different, but compatible types. That's the part I don't know how to express in Go.
For instance, the code below doesn't work (as expected) because the types of array and values are independent of each other. Similar code would work with C++ templates since the compatibility is validated after template instantiation (similar to duck typing). The Go compiler gives out the error invalid argument: arguments to copy result (variable of type []A) and values (variable of type []T) have different element types A and T:
func Prepend[A any, T any](array []A, values ...T) []A {
if len(values) < 1 { return array }
result := make([]A, len(values) + len(array))
copy(result, values)
copy(result[len(values):], array)
return result
}
I've tried making the type T compatible with A with the constraint ~A, but Go doesn't like a type parameter used as type of a constraint, giving out the error type in term ~A cannot be a type parameter:
func Prepend[A any, T ~A](array []A, values ...T) []A {
What's the proper way to declare this type compatibility as generics constraints without resorting to reflection?

This is a limitation of Go's type parameter inference, which is the system that tries to automatically insert type parameters in cases where you don't define them explicitly. Try adding in the type parameter explicitly, and you'll see that it works. For example:
// This works.
func grow(array []Base) []Base {
return Prepend[Base](array, &Foo{x: len(array)})
}
You can also try explicitly converting the *Foo value to a Base interface. For example:
// This works too.
func grow(array []Base) []Base {
return Prepend(array, Base(&Foo{x: len(array)}))
}
Explanation
First, you should bear in mind that the "proper" use of type parameters is to always include them explicitly. The option to omit the type parameter list is considered a "nice to have", but not intended to cover all use cases.
From the blog post An Introduction To Generics:
Type inference in practice
The exact details of how type inference works are complicated, but using it is not: type inference either succeeds or fails. If it succeeds, type arguments can be omitted, and calling generic functions looks no different than calling ordinary functions. If type inference fails, the compiler will give an error message, and in those cases we can just provide the necessary type arguments.
In adding type inference to the language we’ve tried to strike a balance between inference power and complexity. We want to ensure that when the compiler infers types, those types are never surprising. We’ve tried to be careful to err on the side of failing to infer a type rather than on the side of inferring the wrong type. We probably have not gotten it entirely right, and we may continue to refine it in future releases. The effect will be that more programs can be written without explicit type arguments. Programs that don’t need type arguments today won’t need them tomorrow either.
In other words, type inference may improve over time, but you should expect it to be limited.
In this case:
// This works.
func grow(array []*Foo) []*Foo {
return Prepend(array, &Foo{x: len(array)})
}
It is relatively simple for the compiler to match that the argument types of []*Foo and *Foo match the pattern []T and ...T by substitutingT = *Foo.
So why does the plain solution you gave first not work?
// Why does this not work?
func grow(array []Base) []Base {
return Prepend(array, &Foo{x: len(array)})
}
To make []Base and *Foo match the pattern []T and ...T, just substituting T = *Foo or T = Base provides no apparent match. You have to apply the rule that *Foo is assignable to the type Base to see that T = Base works. Apparently the inference system doesn't go the extra mile to try to figure that out, so it fails here.

Related

Go: difference between any and interface in varargs [duplicate]

As generics have been released in Go 1.18 pretty recently, I've started learning them. I generally get the concept, because I have some Java experience from the past. But I don't get some implementation specifics.
For instance: when it's more suitable to use any instead of interface{}? Here's an example:
func printInterface(foo interface{}) {
fmt.Printf("%v\n", foo)
}
func printAny[T any](foo T) {
fmt.Printf("%v\n", foo)
}
func (suite *TestSuite) TestString() {
printInterface("foo")
printAny("foo")
}
Both implementations work. However, if I try to print nil with any-version, I'll get a compile-time error:
cannot infer T.
https://go.dev/play/p/0gmU4rhhaOP
And I won't get this error if I try to print nil with interface{}-version.
So what's the use-case for any? When and which benefits does it bring, compared to simply using interface{}?
I'm asking to provide a specific example, where one implementation is objectively more suitable than another and/or where there is a specific benefit that can be evaluated.
Beside any and interface{} being type aliases — hence, equivalent in usage —, there is a practical difference between any as type parameter and any as regular function argument, as in your example.
The difference is that in printAny[T any](foo T) the type of foo is not any/interface{}, but it's T. And T after instantiation is a concrete type, that may or may not be an interface itself. You can then only pass arguments to an instantiated printAny that can be assigned to that concrete type.
How this impacts your code is most evident with multiple arguments. If we change the function signatures a bit:
func printInterface(foo, bar any) {
fmt.Println(foo, bar)
}
func printAny[T any](foo, bar T) {
fmt.Println(foo, bar)
}
After instantiation:
the function printAny accepts any two arguments of the same type — whichever is used to instantiate T
printInterface, which is equivalent to printInterface(foo, bar interface{}) can still accept two arguments of different types, since both would be individually assignable to any/interface{}.
printInterface(12.5, 0.1) // ok
printInterface(12.5, "blah") // ok, int and string individually assignable to any
printAny(10, 20) // ok, T inferred to int, 20 assignable to int
printAny(10, "k") // compiler error, T inferred to int, "k" not assignable to int
printAny[any](10, "k") // ok, T explicitly instantiated to any, int and string assignable to any
printAny(nil, nil) // compiler error, no way to infer T
printAny[any](nil, nil) // ok, T explicitly instantiated to any, nil assignable to any
A playground: https://go.dev/play/p/pDjP986cj96
Note: the generic version cannot be called with nil without explicit type arguments simply because nil alone doesn't carry type information, so the compiler can't infer T. However nil can be normally assigned to variables of interface type.
any is an alias for interface{}. Spec: Interface types:
For convenience, the predeclared type any is an alias for the empty interface.
Since it is an alias, it doesn't matter which one you use. They are one and the same. They are interchangeable. You can replace one with the other, the code will mean the same.
any is shorter and clearer, but only works from Go 1.18.
Since they are interchangeable, this also works:
func printInterface(foo any) {
fmt.Printf("%v\n", foo)
}
The reason why printAny() doesn't work is due to it being a generic function with a type parameter. To use it, it must be instantiated (its type parameter must be assigned with a known type). Trying to call it with nil carries no type information, so instantiation cannot happen, type inference won't work.
If you call it with a nil value that carries type info, it'll work, or if you specify the type param explicitly (try it on the Go Playground):
printAny((*int)(nil))
printAny[*int](nil)
// Or
var r io.Reader
printAny(r)
And as said, any is interchangeable with interface{}, so you'll have the same code if you swap both occurrences (try this one on the Go Playground):
func printInterface(foo any) {
fmt.Printf("%v\n", foo)
}
func printAny[T interface{}](foo T) {
fmt.Printf("%v\n", foo)
}
Your issue is not related to the usage of any/interface{} — whose difference is purely cosmetic — but it is type inference. As you can see from this playground, if you instantiate your function with an explicit type, like printAny[any](nil) it will work.
If you have a function with generic type you need to specify the types. However the go compiler is very smart and can infer some types for you. But nil alone is impossible to infer.

When is the tilde not necessary in Go generics?

With Golangs new generics we have the tilde operator ~ which will match the underlying type. In what case is it valid to NOT match the underlying type? I'm trying to understand why the current behavior with the tilde is not the default behavior. It seems unnecessary to support both.
For example, why would you write
interface { int }
and not
interface { ~int }
What benefit to you would it be to write a method that is so strict that it could not accept something like
type MyInt int
Why is the tilde behavior not the default, and thus the language would not require another operator?
Not using the ~ operator means you only accept the listed exact types. Why should this matter?
You may want to use the values of the exact types to set to other variables and else type conversion would be required. And because the saying goes "new type, new method set". New types having the same underlying type have their own method sets.
You may want the "original" behavior of the value, which may change if it has a different method set.
For example, let's say you want to print the number like this:
type Num interface{ ~int }
func foo[T Num](v T) {
fmt.Println(v)
}
If MyInt has a String() string method:
type MyInt int
func (m MyInt) String() string { return "bar" }
The output might not be what foo() would want, because the fmt package checks if a printed value has a String() string method, and if so, it is called to acquire its string representation:
foo(1)
foo(MyInt(1))
This will output (try it on the Go Playground):
1
bar
If you only allow int:
type Num interface{ int }
You can still call foo() with a value of type MyInt, using a type conversion:
foo(1)
x := MyInt(1)
foo(int(x))
And output will be what foo() wants, not what MyInt would want (try this one on the Go Playground):
1
1
Yes, this would also be possible if foo() itself would do the conversion, but this clearly documents you want a pure int, with int's behavior, and not something that is an int with a different, custom behavior.
Why is the tilde behavior not the default
Because it would be confusing and semantically unsound to write a function like func Foo[T int](v T) that accepts type parameters that are not int. Then the meaning of int in interface constraints would not be the same as everywhere else. (More on this discussion)
What benefit to you would it be to write a method that is so strict [...]
Indeed if the constraint includes only one exact type, using type parameters is moot. If the type set of the constraint has cardinality 1, you should just remove the type parameter.
A function like:
func Foo[T int](v T)
can only ever be instantiated with exactly int, so it can (and should!) be simply written with regular arguments:
func Foo(v int)
When the type set cardinality is N, which includes single tilde types, but also unions, makes it basically impossible to write exhaustive type switch, since using ~ in case statements is not allowed (yet?):
func Foo[T ~int | ~string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
// how to match other possible types then?
}
}
In this particular case, an exhaustive type switch can be written only if the constraint includes exact types:
func Foo[T int | string](v T) {
switch t := any(v).(type) {
case int: // ok
case string: // ok
default:
panic("should not occur")
}
}
This should not arise frequently in practice: if you find yourself switching on the type parameter, you should ask yourself if the function really needs to be generic. However the use case is relevant when designing your code.
Why is the tilde behavior not the default, and thus the language would not require another operator?
Because if the approximation would be the default unconditionally you could not express the fact that your polymorphic function requires an int and not a MyInt. You would then have to introduce an operator like strict and write %int. Nothing gained.

How to pass type to function argument in Go

ERROR: type CustomStruct is not an expression.
type CustomStruct struct {
}
func getTypeName(t interface{}) string {
rt := reflect.TypeOf(t).Elem()
return rt.Name()
}
getTypeName(CustomStruct)
How can I pass struct type to function without type instance?
This will work
getTypeName((*CustomStruct)(nil))
But I wonder if there is more simple version..
You can't. You can only pass a value, and CustomStruct is not a value but a type. Using a type identifier is a compile-time error.
Usually when a "type" is to be passed, you pass a reflect.Type value which describes the type. This is what you "create" inside your getTypeName(), but then the getTypeName() will have little left to do:
func getTypeName(t reflect.Type) string {
return t.Name()
}
// Calling it:
getTypeName(reflect.TypeOf(CustomStruct{}))
(Also don't forget that this returns an empty string for anonymous types such as []int.)
Another way is to pass a "typed" nil pointer value as you did, but again, you can just as well use a typed nil value to create the reflect.Type too, without creating a value of the type in question, like this:
t := reflect.TypeOf((*CustomStruct)(nil)).Elem()
fmt.Println(t.Name()) // Prints CustomStruct
Lets resurrect this!
The generics proposal for Go got approved, and that's coming, eventually. When this question was first asked, this probably made more sense as a question, but for anyone looking to implement a generics pattern now, I think I've got an alright API for it.
For now, you can't interact with abstract types, but you can interact with methods on the abstract type, and reflect allows you to examine function signatures. For a method, the 0th is the receiver.
type Example struct {int}
type Generic struct{reflect.Type}
func (p Example) Type() {}
func Reflect(generic interface{}) Generic {
real := reflect.TypeOf(generic)
if real.Kind() != reflect.Func || real.NumIn() < 1 {
panic("reflect.Type.In(n) panics if not a func and if n out of bounds")
}
return Generic{real.In(0)}
}
func (g Generic) Make() interface{} {
return reflect.Zero(g.Type).Interface()
}
func main() {
tOfp := Reflect(Example.Type)
fmt.Printf("Name of the type: %v\n", tOfp.Name())
fmt.Printf("Real (initial)value: %v\n", tOfp.Make())
}
Some quick notes:
The structure of "Example" doesn't matter, rather only that it has a method with a non-pointer receiver.
The definition of a type called "Generic" as a struct is to accomplish what I believed OP's actual intent to be.
The above definition of "Generic" is a struct instead of an interface so that it can have its own method set. Defining "Generic" as an interface, and using a methodset specific to each operand-type used with it would make tons of sense.
If you weren't aware, actual generics are coming in Go 1.18. My example above has no linter or compile protection, and will panic at runtime if used incorrectly. It does work, and will let you reason over abstract types while you wait for a native implementation.
Happy Coding!
From Go version 1.18 a new feature Generics has been introduced. In most of the case instead of passing types to function, we can use generics. Then we will also get compile time error instead of runtime error and it's more efficient than reflect also.
Example Code
func HttpGet[T](url, body) T {
var resp T
return T
}
resp := HttpGet[ResponseType]("dummy.example", nil)

How can I return a subtype of the specified return value (in this case interface{})?

I have an interface that defines one parameter to have type func(interface{}, proto.Message) interface{} and I'm trying to pass something of type func reduceMsg(a interface{}, b proto.Message) []*PersistentData to it. This results in the following compiler error:
Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}
What is the reason for this error, and how can I work around it? It seems like returning a more specific type than interface{} should be legal. Here's a simple complete example that illustrates the issue:
package main
import "fmt"
func main() {
var t func() interface{} = func() []string { return []string{} }
fmt.Println(t)
}
The type of the object is the whole function signature. If the signature don't match, then it's not the same type and can't be assigned that way.
Anything can be assigned to the empty interface, because all types satisfy the interface, but in your problem neither type is the empty interface, you just have a function that returns an empty interface.
Not because a part of the function can be assigned to another it makes it the same. The type is the whole function signature. I think it's the same logic behind not being able to assign an int to an int8. You can cast them if you want, but for go, they are separate types and you need to deal with making the necessary conversions to be able to assign them.
What you can do is change your second function signature to return an empty interface like this:
func(interface{}, proto.Message) interface{}
func reduceMsg(a interface{}, b proto.Message) interface{} {
var a []*PersistentData
// do something here
return a
}
This way the function signature is the same, so it's consider the same type and you are returning an []*PersistentData. Of course you will need to do a type assertion before using it as such because the program will treat it as an {}interface because that is the type that the function returned.
Referencing the spec,
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Any typed value may be assigned to the blank identifier.
If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.
Assignability
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
In general, Go doesn't allow you to implicitly convert values from one type to another, with the exception of being able to use concrete-typed objects as though they were interfaces (that they implement).
In this particular case, since your function doesn't actually return an interface{}, the compiler would have to do some extra work to wrap up the return value as an interface{} and return it; if you really want to accomplish what you're trying you can do this explicitly yourself:
type Foo struct {
X int
}
func create(x int) Foo {
return Foo{X: x}
}
func main() {
var f func(int) interface{} = func(x int) interface{} {
return create(x)
}
}
which is basically doing (explicitly) the wrapping operation that you want the runtime to do implicitly.

What's the meaning of interface{}?

I'm new to interfaces and trying to do SOAP request by github
I don't understand the meaning of
Msg interface{}
in this code:
type Envelope struct {
Body `xml:"soap:"`
}
type Body struct {
Msg interface{}
}
I've observed the same syntax in
fmt.Println
but don't understand what's being achieved by
interface{}
Note: Go 1.18 (Q1 2022) does rename interface{} to any (alias for interface{}).
See issue 49884, CL 368254 and commit 2580d0e.
See the last part of this answer.
You can refer to the article "How to use interfaces in Go" (based on "Russ Cox’s description of interfaces"):
What is an interface?
An interface is two things:
it is a set of methods,
but it is also a type
The interface{} type (or any with Go 1.18+), the empty interface is the interface that has no methods.
Since there is no implements keyword, all types implement at least zero methods, and satisfying an interface is done automatically, all types satisfy the empty interface.
That means that if you write a function that takes an interface{} value as a parameter, you can supply that function with any value.
(That is what Msg represents in your question: any value)
func DoSomething(v interface{}) {
// ...
}
func DoSomething(v any) {
// ...
}
Here’s where it gets confusing:
inside of the DoSomething function, what is v's type?
Beginner gophers are led to believe that “v is of any type”, but that is wrong.
v is not of any type; it is of interface{} type.
When passing a value into the DoSomething function, the Go runtime will perform a type conversion (if necessary), and convert the value to an interface{} value.
All values have exactly one type at runtime, and v's one static type is interface{} (or any with Go 1.18+).
An interface value is constructed of two words of data:
one word is used to point to a method table for the value’s underlying type,
and the other word is used to point to the actual data being held by that value.
Addendum: This is were Russ's article is quite complete regarding an interface structure:
type Stringer interface {
String() string
}
Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data.
Assigning b to an interface value of type Stringer sets both words of the interface value.
The first word in the interface value points at what I call an interface table or itable (pronounced i-table; in the runtime sources, the C implementation name is Itab).
The itable begins with some metadata about the types involved and then becomes a list of function pointers.
Note that the itable corresponds to the interface type, not the dynamic type.
In terms of our example, the itable for Stringer holding type Binary lists the methods used to satisfy Stringer, which is just String: Binary's other methods (Get) make no appearance in the itable.
The second word in the interface value points at the actual data, in this case a copy of b.
The assignment var s Stringer = b makes a copy of b rather than point at b for the same reason that var c uint64 = b makes a copy: if b later changes, s and c are supposed to have the original value, not the new one.
Values stored in interfaces might be arbitrarily large, but only one word is dedicated to holding the value in the interface structure, so the assignment allocates a chunk of memory on the heap and records the pointer in the one-word slot.
Issue 33232 seems to point out to any as an alias to interface{} in Go 1.18 (Q1 2022)
Russ Cox explains:
'any' being only for constraints is a detail that will be in every writeup of generics - books, blog posts, and so on.
If we think we are likely to allow it eventually, it makes sense to allow it from the start and avoid invalidating all that written material.
'any' being only for constraints is an unexpected cut-out that reduces generality and orthogonality of concepts.
It's easy to say "let's just wait and see", but prescribing uses tends to create much more jagged features than full generality. We saw this with type aliases as well (and resisted almost all the proposed cut-outs, thankfully).
If 'any' is allowed in generics but not non-generic code, then it might encourage people to overuse generics simply because 'any' is nicer to write than 'interface{}', when the decision about generics or not should really be made by considering other factors.
If we allow 'any' for ordinary non-generic usage too, then seeing interface{} in code could serve as a kind of signal that the code predates generics and has not yet been reconsidered in the post-generics world.
Some code using interface{} should use generics. Other code should continue to use interfaces.
Rewriting it one way or another to remove the text 'interface{}' would give people a clear way to see what they'd updated and hadn't. (Of course, some code that might be better with generics must still use interface{} for backwards-compatibility reasons, but it can still be updated to confirm that the decision was considered and made.)
That thread also includes an explanation about interface{}:
It's not a special design, but a logical consequence of Go's type declaration syntax.
You can use anonymous interfaces with more than zero methods:
func f(a interface{Foo(); Bar()}) {
a.Foo()
a.Bar()
}
Analogous to how you can use anonymous structs anywhere a type is expected:
func f(a struct{Foo int; Bar string}) {
fmt.Println(a.Foo)
fmt.Println(a.Bar)
}
An empty interface just happens to match all types because all types have at least zero methods.
Removing interface{} would mean removing all interface functionality from the language if you want to stay consistent / don't want to introduce a special case.
interface{} means you can put value of any type, including your own custom type. All types in Go satisfy an empty interface (interface{} is an empty interface).
In your example, Msg field can have value of any type.
Example:
package main
import (
"fmt"
)
type Body struct {
Msg interface{}
}
func main() {
b := Body{}
b.Msg = "5"
fmt.Printf("%#v %T \n", b.Msg, b.Msg) // Output: "5" string
b.Msg = 5
fmt.Printf("%#v %T", b.Msg, b.Msg) //Output: 5 int
}
Go Playground
There are already good answers here. Let me add my own too for others who want to understand it intuitively:
Interface
Here's an interface with one method:
type Runner interface {
Run()
}
So any type that has a Run() method satisfies the Runner interface:
type Program struct {
/* fields */
}
func (p Program) Run() {
/* running */
}
func (p Program) Stop() {
/* stopping */
}
Although the Program type has also a Stop method, it still satisfies the Runner interface because all that is needed is to have all of the methods of an interface to satisfy it.
So, it has a Run method and it satisfies the Runner interface.
Empty Interface
Here's a named empty interface without any methods:
type Empty interface {
/* it has no methods */
}
So any type satisfies this interface. Because, no method is needed to satisfy this interface. For example:
// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty
a = 5
a = 6.5
a = "hello"
But, does the Program type above satisfy it? Yes:
a = Program{} // ok
interface{} is equal to the Empty interface above.
var b interface{}
// true: a == b
b = a
b = 9
b = "bye"
As you see, there's nothing mysterious about it but it's very easy to abuse. Stay away from it as much as you can.
https://play.golang.org/p/A-vwTddWJ7G
It's called the empty interface and is implemented by all types, which means you can put anything in the Msg field.
Example :
body := Body{3}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:3}
body = Body{"anything"}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:"anything"}
body = Body{body}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:main.Body{Msg:"anything"}}
This is the logical extension of the fact that a type implements an interface as soon as it has all methods of the interface.
From the Golang Specifications:
An interface type specifies a method set called its interface. A
variable of interface type can store a value of any type with a method
set that is any superset of the interface. Such a type is said to
implement the interface. The value of an uninitialized variable of
interface type is nil.
A type implements any interface comprising any subset of its methods
and may therefore implement several distinct interfaces. For instance,
all types implement the empty interface:
interface{}
The concepts to graps are:
Everything has a Type. You can define a new type, let's call it T. Let's say now our Type T has 3 methods: A, B, C.
The set of methods specified for a type is called the "interface type". Let's call it in our example: T_interface. Is equal to T_interface = (A, B, C)
You can create an "interface type" by defining the signature of the methods. MyInterface = (A, )
When you specify a variable of type, "interface type", you can assign to it only types which have an interface that is a superset of your interface.
That means that all the methods contained in MyInterface have to be contained inside T_interface
You can deduce that all the "interface types" of all the types are a superset of the empty interface.
An example that extends the excellent answer by #VonC and the comment by #NickCraig-Wood. interface{} can point to anything and you need a cast/type assertion to use it.
package main
import (
. "fmt"
"strconv"
)
var c = cat("Fish")
var d = dog("Bone")
func main() {
var i interface{} = c
switch i.(type) {
case cat:
c.Eat() // Fish
}
i = d
switch i.(type) {
case dog:
d.Eat() // Bone
}
i = "4.3"
Printf("%T %v\n", i, i) // string 4.3
s, _ := i.(string) // type assertion
f, _ := strconv.ParseFloat(s, 64)
n := int(f) // type conversion
Printf("%T %v\n", n, n) // int 4
}
type cat string
type dog string
func (c cat) Eat() { Println(c) }
func (d dog) Eat() { Println(d) }
i is a variable of an empty interface with a value cat("Fish"). It is legal to create a method value from a value of interface type. See https://golang.org/ref/spec#Interface_types.
A type switch confirms i interface type is cat("Fish") . See https://golang.org/doc/effective_go.html#type_switch. i is then reassigned to dog("Bone"). A type switch confirms that i interface’s type has changed to dog("Bone") .
You can also ask the compiler to check that the type T implements the interface I by attempting an assignment: var _ I = T{}. See https://golang.org/doc/faq#guarantee_satisfies_interface and https://stackoverflow.com/a/60663003/12817546.
All types implement the empty interface interface{}. See https://talks.golang.org/2012/goforc.slide#44 and https://golang.org/ref/spec#Interface_types . In this example, i is reassigned, this time to a string "4.3".i is then assigned to a new string variable s with i.(string) before s is converted to a float64 type f using strconv. Finally f is converted to n an int type equal to 4. See What is the difference between type conversion and type assertion?
Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly. See https://golang.org/doc/faq#generics.
Interface is a type which is unknown at compile time
It is a contract between object and the struct type to satisfy with common functionality
or
common functionality acting on different types of struct objects
for example in the below code PrintDetails is a common functionality acting on different types of structs as Engineer,Manager,
Seniorhead
please find the example code
interface examplehttps://play.golang.org/p/QnAqEYGiiF7
A method can bind to any type(int, string, pointer, and so on) in GO
Interface is a way of declear what method one type should have, as long as A type has implement those methods, this can be assigned to this interface.
Interface{} just has no declear of method, so it can accept any type

Resources