Go method Call and interface

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

When comparing C + + and go, it is common to say that go does not support inheritance and polymorphism, but it implements similar language features through composition and interfaces. Summarize why go does not support: (1) First the struct is a value type, and the assignment and the parameter copy all the contents. The memory layout of a struct is almost identical to C, with no additional object information, such as pointers to virtual function tables. (2) Next go does not support implicit type conversions, so pointing a pointer to a subclass with a base class will compile an error.

the basic principle of the Go Program abstraction relies on interfaces rather than implementations, with precedence over combinations rather than inheritance.

method invocation of a struct

The method call of the object is equivalent to the syntax sugar of the normal function call. The invocation of the value method is m.Value() equivalent to func Value(m M) putting the object instance m as the first argument stack of a function call, when M is called receiver. A pointer to an instance or instance can actually call all methods, except that the receiver copied to the function is different.

When value is called through instance m, and when value is called through pointer p, receiver is M and *p, that is, the M instance itself is copied. So receiver is a copy of the M instance and their address is different. When pointer is called through instance m, and when pointer is called through pointer p, all copies are &m and P, that is, the copy is a pointer to M, and the address of the M instance is returned.

type M struct {    a int}func (m M) Value() string {return fmt.Sprintf("Value: %p\n", &m)}func (m *M) Pointer() string {return fmt.Sprintf("Pointer: %p\n", m)}var m Mp := &m      // p is address of m 0x2101ef018m.Value()    // value(m) return 0x2101ef028m.Pointer()  // value(&m) return 0x2101ef018p.Value()    // value(*p) return 0x2101ef030p.Pointer()  // value(p) return 0x2101ef018
If you want to modify the value of the object in the method can only use pointer receiver, the object is larger to avoid copying also use pointer receiver.

Method Set Understanding

In the example above, all methods can be called by instance m and P, which are automatically converted by the compiler. In many go grammar books there is the concept of a method set. The set of type T methods contains all receiver t methods, and the type *t contains all receiver T and *t methods. This phrase has never been understood, since all methods of T and *t can be accessed through instances and pointers, and what is the meaning of the method set.

Methods that are defined in the M type can also be called in addition to access by instance and instance pointers method expression . At this point the pointer is not visible to the M type.

(M).Value(m)       // valid(M).Pointer(m)     // invalid M does not have Pointer(*M).Value(&m)     // valid(*M).Pointer(&m)   // valid

Then explain the problem of receiver replication for method value. Here U. The type returned by test is similar to the type of funcval returned by the closure, which is the FuncVal{method_address, receiver_copy} object. So the example in Mvalue already contains a copy of the instance U. Of course, if receiver of the test method is *user, the result will be different.

u := User{1}     // User{Id int}mValue := u.Test // func(s User) Test() {fmt.Println(s.Id)}u.Id = 2u.Test()  // output: 2mValue()  // output: 1

Anonymous fields and combinations

Go has no inheritance, but it has a struct embedded. When a type T is anonymously embedded in another type of M, the T method is copied to the M method table. This is based on the rules of the method set, if M contains *t, then M contains all the methods on T and *t.

with the anonymous field, go implements a reuse capability similar to inheritance, and can define the same method name on M to implement override.

Interface interface Implementation

Go interface is a built-in type that belongs to the duck-typing type of the dynamic style. Interface as a collection of method signatures, any type of method set, as long as it has all the corresponding methods, means that it implements the interface.

Interface Bottom Structure

Interface is a struct that contains two members. Based on whether the interface contains methods, the bottom layer is divided into two structures. Eface is mainly to save the type information, after summing up the reflection of the specific, here first summarizes the iface with the method. Structure definition in the runtime2.go obvious iface consists of two parts, the data field holds metadata, tab describes the interface.

type eface struct {    _type *_type    data unsafe.Pointer}type iface struct {    tab *itab    data unsafe.Pointer}
type itab struct {  inter *interfacetype // 保存该接口的方法签名  _type *_type // 保存动态类型的type类型信息  link *itab // 可能有嵌套的itab  bad int32  unused int32  fun [1]uintptr  // 保存动态类型对应的实现}type interfacetype struct {  type _type  mhdr []imethod}

To understand Iface's data structure, find an example of Donald's interface interface, and look at what the Iface data is all about in gdb. First dd=&DonalDuck{} , this type of method set includes the MakeFun Walking Speaking implementation of the Duck and Actor two interfaces.

type Duck interface {GaGaSpeaking()OfficialWalking()}type Actor interface {MakeFun()}type DonaldDuck struct {height uintname   string}func (dd *DonaldDuck) GaGaSpeaking() { fmt.Println("DonaldDuck gaga") }func (dd *DonaldDuck) OfficialWalking() { fmt.Println("DonaldDuck walk") }func (dd *DonaldDuck) MakeFun() { fmt.Println("DonaldDuck make fun") }func main() {dd := &DonaldDuck{10, "tang lao ya"}var duck Duck = ddvar actor Actor = ddduck.GaGaSpeaking()actor.MakeFun()dd.OfficialWalking()}

It can be seen that when DD is assigned to the interface duck, the address stored by the data field of the interface Duck is the address pointed to by the DD object. The Inter field in the tab Field holds the two method declarations that implement this interface, where name holds the name of the method. The Func pointer to the tab field points to the specific implementation, which is the code snippet address for the symbol .text .

The conversion of the specific T type to iface involves copying of 3 content (1) The Func field of Iface's tab field holds the method set of type T, which is the implementation of the method that the Tab field Inter declares. (2) The Iface data field pointer points to a copy of the object used for assignment. (3) Iface the _type field of the tab field to save _type of type T.

Compile-time detection

When the T type does not implement all the methods in the I interface, the assignment from T to I throws a TypeAssertionError compilation error. Check the method in the function Additab, that is, to see the _type method Table of type T uncommenttype contains all the IMethod in the I interface interfacetype , while copying the implementation of the T type to the method to the table that the TAB's func points to.

type _type struct {size       uintptrptrdata    uintptr // size of memory prefix holding all pointershash       uint32_unused    uint8align      uint8fieldalign uint8kind       uint8alg        *typeAlggcdata  *byte_string *stringx       *uncommontypeptrto   *_typezero    *byte // ptr to the zero value for this type}type uncommontype struct {name    *stringpkgpath *stringmhdr    []method}

Three differences in method tables

1) Each specific T type structure corresponds to the method table uncommontype , and the type of the method set is here. The method and Methodbyname methods in the reflect package are implemented by querying this table. Each item in the table is method .

type method struct {name    *stringpkgpath *stringmtyp    *_typetyp     *_typeifn     unsafe.Pointertfn     unsafe.Pointer}

2) Itab's interfacetype domain is a method table that declares all the methods of the interface, each of which is imethod visible 没有实现只有声明 .

type imethod struct {  name *string  pkgpath *string  _type *type}

3) The func field of Itab is also a method table, and each item in the table is a function pointer, that is 只有实现没有声明 . That is, the assignment of a specific type of implementation, that is, the function pointer is copied to the Itab's func domain.

Run-time Convt2i

Go-internals analyzes the syntax tree nodes that the go compiler generates at compile time. When the T2i is converted, getitab it produces an intermediate state itab . And the call convT2I completes the memory copy of the data domain of the runtime and the assignment of the middle State itab to the tab field .

You can see the assignment of the getitab implementation address to tab FNC[0] of the method table of type T. Complete the getiab _type information that requires the type T, and the InterfaceType method table for the I interface type, which are provided at compile time. Therefore, the dynamic nature of the interface and the implementation of reflection are based on the type information provided by the runtime at compile time.

func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {..  m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+      uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys))  m.inter = inter  m._type = typ...  for k := 0; k < ni; k++ {    for ; j < nt; j++ {     *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn    }    goto nextimethod   }  // didn't find method  if !canfail {    panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})  }  return m}

The last convT2I memory copy of the existing data, which is visible as a copy of the type T object.

func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) {  tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))...  if x == nil {    x = newobject(t)  }  typedmemmove(t, x, elem)  pi.tab = tab  pi.data = x  return}

When you summarize the assignment of an object to an interface, the compile time checks whether the object implements all of the interface's methods. The runtime copies the data, type, and implementation of the object into the Iface interface.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.