Interface in Go

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

With 9 years of c++,1 C #, recently switched to go language development, deeply felt that the go language design is simple, its design purpose is not more, it greatly accelerates the development speed.

The go language absorbs many of the advantages of modern languages, and a more important feature is programming based on interfaces, which are the first citizens of the program world, a bit like the scalar language. The language prototype that implements this interface is interface.

Interface-based programming

The interface is not supported in C + +, the implementation of the interface is implemented by pure virtual functions, C # has an interface, but it is considered an interface is a capability of the object, which is a great progress, but it is not flexible, such as

 PublicInterface ifile{ Public int Read(stringFilePath,intLen Public int Write(stringFilePath,intLen)} This interface implements reading Len bytes of data from a file, returning actual data, and writing Len bytes of data, returning the actual number of data written Public classcdatanode:ifile{ Public int Read(stringFilePath,intLen) {...} Public int Write(stringFilePath,intLen) {...}} This allows the cdatanode to be used directly where the IFile interface is supported

This code is written for a long time, but if you find ifile this size is too large, some places just need to read, some places need write, in C # can only be

publicInterface IReadpublicInterface IWritepublicInterface IFile:IRead,IWrite

This is not required in go, only the iread and Iwrite interfaces need to be declared, IFile can be converted directly to Iread and Iwrite, which is more flexible.

 PackageMainImport("FMT")typeIFileInterface{Read (int)intWrite (int)int}typeRwfilestruct{}func(rw rwfile) Read (int)int{FMT. Println ("Rwfile read")return0}func(rw rwfile) Write (int)int{FMT. Println ("Rwfile write")return0}typeIreadInterface{Read (int)int}typeIwriteInterface{Write (int)int}funcTestInterface () {varRwinterface iFile = rwfile{} rwinterface.read(0) Rwinterface.write(0)varRinterface Iread = Rwinterface rinterface.read(0)varWinterface iwrite = Rwinterface winterface.write(0)}

Modules rely on interfaces, and go is not support inheritance, only support combinations, inheritance is a strong relationship, once it is difficult to change, or the cost of change is very high, the combination is a weak relationship, more loosely.

Inheritance and Polymorphism Properties

Inheritance and polymorphism are a very good feature of object-oriented design, which can be a better abstraction of the framework, allowing modules to rely on interfaces, rather than relying on specific implementations.

 PackageMainImport("FMT")typeIAnimalInterface{Speak ()string}typeDogstruct{}func(d dog) speak ()string{return "woof!"}typeCatstruct{}func(c cat) speak ()string{return "meow!"}typeCoderstruct{}func(c coder) speak ()string{return "Hello world!"}typeSupercoderstruct{Coder//If the variable name is not given, the compiler generates a coder coder variable, and then its syntax sugar is access to the variable, directly accessing its internal member variables without having to go through the. Coder. }func(s Supercoder) Sayhi () {fmt. Println ("Super coder say hi")}funcPolymorphic () {Animals: = []ianimal{dog{}, cat{}, coder{}, supercoder{}} for_, Animal: =RangeAnimals {FMT. Println (Animal.speak ())}}

Depends on the interface to implement, as long as the implementation of this interface can be considered to assign to this port, to implement dynamic binding. Supercoder here can be considered as inheritance and coder, but it adds a new method Sayhi, the original Speak method does not change, so it does not need to rewrite.
Go is not inherited, anonymous member variables are just a syntactic sugar, not inherited

typestruct{    int}typestruct{    cat}var c cat = dog{}//编译错误var pc *cat = &dog{}//编译错误var pc *cat = (*cat)(&dog{})//编译错误

In C + +, you can use a base-class pointer to point to an object of a subclass, but in go it is considered to be two types and cannot be converted.
Fundamentally, structs have no virtual table pointers in go, which is only interface, so it's two separate types that can't be converted to each other.

Use of interface

The interface features are:
* is a set of function signatures
* is a type

interface{}

interface{} is a special kind of interface because it does not implement any type, so all types of variables can be assigned to it, a bit like the C # object, which is the base class for all objects.

package mainimport (    "fmt")func PrintAll(vals []interface{}) {    forrange vals {        fmt.Println(val)    }}func main() {    names := []string{"stanley""david""oscar"}    PrintAll(names)}

At first I was wondering why I couldn't compile it, and then think about it. However, here Printall receives a "[]interface{}" type, the input parameter is a "[]string" type, two are different types, cannot be assigned. So the right thing to do is

package  Main import  ( "FMT" ) func  Printall (Vals []interface  {}) {for  _, Val: = Span class= "Hljs-keyword" >range  vals {fmt. Println (val)}}func  Main () {names: = []string  {  "Stanley" ,  "David" ,  "Oscar" } //printall (names)  vals: = make  ([]interface  {}, len  (names)) for  i, V: = range  names {vals[i] = v} printal L (Vals)}  

Because []interface{} is also a type, it can be assigned to interface{}.

interface{} usage

There is a need for a JSON parsing called a map, because the data format is changeable, using interface{}, call the library function Unmarshaljson.

 PackageMainImport("Encoding/json"    "FMT"    "Reflect")//start with a string representation of our JSON datavarinput =' {' created_at ': ' Thu 00:00:01 +0000 '} 'funcMain () {//Our target would be being of type map[string]interface{}, which is a    //Pretty generic type that would give us a hashtable whose keys    //Is strings, and whose values are of type interface{}    varValMap[string]Interface{}ifERR: = json. Unmarshal ([]byte(input), &val); Err! =Nil{Panic(ERR)} Fmt. Println (Val) forK, V: =Rangeval {fmt. Println (k, reflect. TypeOf (v))}} returns the resultMap[Created_at:thu May toxx: xx:+0000 -]created_atstring

Notice that the time here is a special format, which is not the same as normal, so the result of the return is a string type instead of a time type. It is also problematic to change the map's data to times in a timely manner, because it is not a standard timing format and throws an exception.
Interfaces that can be considered for implementing JSON

typeinterface {    UnmarshalJSON([]byte) error}func (t *Timestamp) UnmarshalJSON(b []byte) error {    string(b[1:len(b)-1]))    ifnil {        return err    }    *t = Timestamp(v)    returnnil}

The map above is normal and the type of return is the time type.

# # interface{} can generally be used as a function's entry parameter, but it is best not to be a function's return value.
There is a need to design an API that translates HTTP request requests into one of the data type formats, possibly in many different formats.
Because the returned data format is not fixed, it is best to use interface{} format.

GetEntity(*http.Request) (interface{}, error)caller:switch v:Get(r).type(){    int:        ...    string:        ...}

This is very bad, because each time you add a new type, the caller needs to change, do not meet the open and close principle, the correct way is

type Entity interface {    UnmarshalHTTP(*http.Request) error}func GetEntity(r *http.Request, v Entity) error {    return v.UnmarshalHTTP(r)}caller:var u Userif err := GetEntity(req, &u); err != nil {    ...}其中User需要实现这个接口func (u *User) UnmarshalHTTP(r *http.Request) error {   ...}

The benefit of adding interface{} as a parameter instead of a return value is to add the new type simply by implementing the entity interface, and then adding a call to this type without modifying the internal implementation of the getentity.

The underlying implementation of interface

Let's take a look at an example and see how this can be achieved.

typeinterface {    string}typeuint64funcstring {    return strconv.Uitob64(i.Get(), 2)}funcuint64 {    returnuint64(i)}

Create a UInt64 with an initial value of 200

b := Binary(200)

Its memory model is as follows:

Assign B to an interface at this point:

s := Stringer(b)//如果不能转换会抛出exception


Interface S consists of two members,
* The first is itable, a bit like C + + vtable, holds a series of function objects, the first is type, through which it can find which type it belongs to, this is the itable first value of all interface, The other is the actual implementation of the function corresponding to the interface type, and we can see the binary implementation of string (). The Get function is implemented in binary because it is not a stringer interface, so it is not put here.
How is itable generated? It is generated dynamically at run time, first of each type, and the compiler generates meta for it, which contains all of the functions it supports and member variables, and when an object is assigned to interface, Runtime iterates through the function signature of the entire object to find a function signature that matches the interface, and if all can match it continues, otherwise throws an exception (if the failure is not checked), and assigns one interface to the other interface.
Assuming that the type of the variable has m functions, interface has n need to support the signature, then the algorithm each match once, the complexity of O (MN), go in it will each function signature collection to sign, so that the complexity of matching is only O (m+n).
* Another is the actual data, here it will create a new value, so the modification of B will not affect the interface

Stringstring {    return2)}ps := Stringer(&b)

In this case, the data section of PS holds a pointer to B, because it is a pointer that comes in when the conversion is made.

Summarize

    • All assignments in the Go language are value copies
    • Interface is a type of function collection
    • The itable of this interface is preserved in the interface, and a copy of the assigned data is saved in Idata.
    • interface as an entry function for a parameter, not as a return value.
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.