This is a creation in Article, where the information may have evolved or changed.
1. Interface is a type
1234 |
type Interface { int} |
First, interface is a type , from its definition can be seen to use the type keyword, more accurately said interface is a type with a set of methods , these methods define the behavior of interface.
Go allows interface without any method, this type of interface is called empty interface.
If a type implements all the methods in a interface, we say that the type implements the interface, so all types implement the empty interface, because any one type implements at least 0 methods. Go does not have an explicit keyword to implement interface, just implement the method interface contains.
2. The interface variable stores the value of the implementing person
1234567891011121314151617181920212223242526272829 |
//1typeIInterface{Get ()intSet (int)}//2typeSstruct{Ageint} func(s s) Get()int {returnS.age} func(S *s) Set(age int) {S.age = age}//3 func F(i i) {I.set (Ten) FMT. Println (I.get ())} func main() {s: = s{} f (&s)//4} |
This code defines the #1
interface I, in the #2
struct S implementation of the I definition of the two methods, and then in the #3
definition of a function f parameter type is i,s implementation of I of the two way to say S is the implementation of I, execute f(&s)
it's over. The use of the interface type.
The important use of interface is reflected in the parameters of function f , if there are multiple types that implement a interface, these types of values can be stored directly using the interface variable .
1234 |
S: = s{}var//assignment S to iFMT. Println (I.get ()) |
It is not difficult to see that the interface variable stores an object value that implements the interface type, which is duck typing. When using interface, you do not need to explicitly declare on the struct which interface to implement, just implement the method in the corresponding interface, go will automatically check interface, and at run time from other types to interface Automatic conversion, even if more than one interface,go is implemented, is automatically converted when the corresponding interface is used, which is the magic of interface.
3, how to determine which type of interface variable is stored
When a interface is implemented by multiple types, sometimes we need to differentiate what type of value the interface variable stores, and the way go can be comma, ok
distinguished value, ok := em.(T)
:em is a variable of type interface, T represents the type to assert, Val The UE is the value stored by the interface variable, and OK is the bool type that indicates whether the assertion is of type T.
1234 |
if t, OK: = I. (*S); OK { FMT. Println ("s implements I", T)} |
OK is true to indicate that I is storing a value of type *s, false is not, and this ability to differentiate is called type assertions.
If you need to differentiate between multiple types, you can use a switch assertion, which is simpler and more straightforward, and can only be used in a switch statement.
1234567 |
switch t: = i (type) {case *s: fmt. Println ("I store *s", T) case *r: fmt. Println ("I store *r", T)} |
4, the Empty interface
interface{}
is an empty interface type, according to the previous definition: If a type implements all the methods of a interface, it says that the type implements this interface, the empty interface has no method, so it can be assumed that all types are implemented interface{}
. If a function parameter is defined as a interface{}
type, the function should be able to accept any type as its argument.
12 |
funcdosomethinginterface{}) { } |
If the function's parameter V can accept any type, then when the function is called, does the function internal v represent any type? Not, although the parameters of a function can accept any type, it does not mean that V is any type, in the function dosomething Internal v is just a interface type, and the function can accept that any type that is passed to the function when go executes is automatically converted to interface{}
. How the go is converted, and the value of the V store is exactly how it can be accepted for any type of interest can be seen in Russ Cox's implementation of the interface.
Since an empty interface can accept any type of argument, can a interface{}
type of slice accept any type of slice?
12345678910 |
func Printall (Vals []interface{}) //1 for Range Vals {fmt. Println (val)}}funcmain(){names: = []string{"Stanley" "David""Oscar"}printall (Names)} |
The above code is modified according to our assumptions, and after execution, it will report an cannot use names (type []string) as type []interface {} in argument to printAll
error, why?
This error indicates that go did not help us automatically convert slice to interface{}
type slice, so something went wrong. go does not interface{}
convert slice that are of type . Why go does not help us automatic conversion, at the beginning I was also very curious, finally finally found the answer in go wiki https://github.com/golang/go/wiki/InterfaceSlice the main idea is to interface{}
occupy two words of storage space, One is its own methods data, a pointer to its stored value, that is, the value stored by the interface variable, so slice []interface{} has a fixed length N*2
, but the length of the]t is the size of the N*sizeof(T)
two slice actual stored values Small is different (the article only describes the differences between the two slice, as to why the conversion can not be guessed the cost of runtime conversion is relatively large).
But we can manually convert to achieve our goal.
12345 |
var dataslice []int = foo ()var interfaceslice []interfacemake ([] Interfacelen(dataslice))forrange Dataslice {interfaceslice[i] = d} |
5. How receiver for interface is chosen
In our example above, the invocation of F is f(&s)
the pointer type of s, why can't it be f(s)
, what if the S is wrong? Change to F (s) and execute the code.
12 |
Cannot use S (Type S) as type I in argument to F:s does not implement I (Set method have pointer receiver) |
This error means that S does not implement I, where is the problem? The key point is that receiver of the set method in S is a pointer *s .
Interface definition does not strictly specify the method of implementation receiver is a value receiver or pointer receiver, the above code of the Set receiver is pointer, that is, the implementation of the two methods of I Receiver One is value one is pointer, the use f(s)
of the situation call, passed to F is a copy of S, in the copy of S to I conversion, the copy of S does not satisfy the Set method receiver is a pointer, there is no There is realization I. functions in Go are passed by value, which is passed by.
What if receiver is value, the function is called in the form of pointer?
123456789101112131415161718192021222324252627 |
typeIInterface{Get ()intSet (int)}typeSsstruct{Ageint} func (S SS) Get() int {returnS.age} func (S SS) Set(age int) {S.age = age} func F(i i) {I.set (Ten) FMT. Println (I.get ())} func main() {ss: = ss{}f (&SS)//ponterF (SS)//value} |
The method receiver for the SS of I is the value receiver, and the execution code can see that both pointer and value can be executed correctly.
What is the cause of this phenomenon?
If you press pointer, go will automatically convert, because with pointers you can always get what the pointer points to, and if it is a value call, go will not know what the original value of value is, because value is a copy. Go will implicitly convert the pointer to value, but not vice versa .
For receiver is the method of value, any change to value within method does not affect the value that the caller sees, which is passed by value.
Another example of the above phenomenon is that from https://play.golang.org/p/TvR758rfre
123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
PackageMainImport("FMT")typeAnimalInterface{Speak ()string}typeDogstruct{} func (d Dog) Speak() string {return "woof!"}typeCatstruct{}//1 func (c *cat) Speak() string {return "meow!"}typeLlamastruct{} func (l Llama) Speak() string {return "?????"}typeJavaprogrammerstruct{} func (J Javaprogrammer) Speak() string {return "Design patterns!"} func main() {Animals: = []animal{dog{}, cat{}, llama{}, javaprogrammer{}} for_, Animal: =RangeAnimals {FMT. PRINTLN (animal. Speak ())}} |
#1
Cat's speak receiver is the value of the slice,cat of Pointer,interface Animal, which is also unable to execute due to receiver inconsistency.
Resources
- Https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.6.md
- Http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
- Https://tour.golang.org/methods/15
- https://www.miek.nl/go/#interfaces
- Https://github.com/golang/go/wiki/InterfaceSlice
- Https://play.golang.org/p/TvR758rfre
- Https://golang.org/doc/effective_go.html#interfaces
- Http://en.wikipedia.org/wiki/Duck_typing
The code used in the article
Click to download the source package