Go Language Interface detailed

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

Interface

Go language inside the most exquisite design should be counted interface, it makes object-oriented, content organization implementation is very convenient, when you read this chapter, you will be interface clever design to be impressed.

What is interface

Simply put, interface is a group of method combinations, and we define a set of behaviors for an object by interface.

In the last example of our previous chapter, both student and employee can sayhi, although their internal implementations are different, but that doesn't matter, it's important that they all say hi.

Let's continue to do more expansion, student and employee implement another method sing, and then student implementation method Borrowmoney and employee implementation spendsalary.

This student implements three methods: Sayhi, Sing, Borrowmoney, and employee realizes Sayhi, Sing, Spendsalary.

The combination of the above methods is called interface (implemented by object student and employee). For example, student and employee both implement Interface:sayhi and sing, which is the interface type of the two objects. The employee did not implement this interface:sayhi, sing, and Borrowmoney because the employee did not implement the Borrowmoney method.

Interface type

The

Interface type defines a set of methods that implement this interface if an object implements all the methods of an interface. A detailed syntax reference is given in the following example

Type Human struct {name string age int phone String}type Student struct {Human//anonymous field Human School string Loan Float32}type Employee struct {Human//anonymous field Human Company string Money Float32}//human Object Implementation Sayhi method func (H * Human) Sayhi () {fmt.    Printf ("Hi, I am%s can call me on%s\n", H.name, H.phone)}//Human Object Implementation Sing method func (H *human) Sing (lyrics string) { Fmt. The}//human object implements the Guzzle method ("La La, la la, Los Angeles, La La la Println), lyrics) *human (guzzle string) {FMT . Println ("Guzzle guzzle guzzle ...", Beerstein)}//Employee Overloads Human Sayhi method func (E *employee) Sayhi () {fmt. Printf ("Hi, I am%s, I work in%s." Call me on%s\n ", E.name, E.company, E.phone)//This sentence can be divided into multiple lines}//student implement Borrowmoney Square Law func (S *student) Borrowmoney (amount float32) {S.loan + = amount//(again and again and ...)} The Employee implements the Spendsalary method func (E *employee) spendsalary (amount float32) {e.money-= amount//More vodka!!! Get me through the day!} Define INTERFACEType Men Interface {sayhi () Sing (lyrics string) guzzle (Beerstein string)}type Youngchap interface {sayhi () Sing (song string) Borrowmoney (amount float32)}type Elderlygent Interface {sayhi () Sing (song string) spends Alary (Amount float32)}

By the above code we can know that interface can be implemented by arbitrary objects. We see the men interface above being implemented by human, student and employee. Similarly, an object can implement any number of interface, such as the above student implements the men and Youngchap two interface.

Finally, any type implements the Null interface (we define this: interface{}), which is the interface with 0 method.

Interface value

So what's the value of interface inside? If we define a interface variable, then the variable can have any type of object that implements the interface. For example, in the above example, we define a men interface type of variable m, then M can store human, student, or employee values.

Because M is capable of holding these three types of objects, we can define a slice that contains elements of the men type, which can be assigned to objects of any structure that implements the men interface, which is different from the slice in our traditional sense.

Let's take a look at the following example:

Package Mainimport "FMT" type Human struct {name string age int phone String}type Student struct {Human//anonymous Word Segment School string loan Float32}type Employee struct {Human//anonymous field company string money Float32}//human implementation Sayh I method func (H Human) Sayhi () {fmt. Printf ("Hi, I am%s can call me on%s\n", H.name, H.phone)}//human implement Sing method func (H Human) Sing (lyrics string) {fmt. Println ("La La L.A. la la ...", lyrics)}//employee overloaded human Sayhi method func (E Employee) Sayhi () {fmt. Printf ("Hi, I am%s, I work in%s." Call me on%s\n ", E.name, E.company, E.phone)}//Interface men were human,student and employee implementations//Because these three types implement both methods type Men interface {Sayhi () Sing (lyrics string)}func main () {Mike: = Student{huma n{"Mike", "222-222-xxx"}, "MIT", 0.00} PAUL: = student{human{"Paul", "111-222-xxx"}, "Harvard", sam: =  employee{human{"Sam", "444-222-xxx"}, "Golang Inc.", "222-444-xxx" tom: = employee{human{"Tom", PNs, "Things"}    Ltd. ", 5000}Defining the men type of variable i var i men//i can store student i = Mike Fmt. Println ("This is Mike, a Student:") I.sayhi () i.sing ("November Rain")//i can also store employee i = Tom fmt. Println ("This is Tom, a Employee:") I.sayhi () i.sing ("Born to Be Wild")//defines the slice men fmt.    PRINTLN ("Let's use a slice of the men and see what Happens") x: = Make ([]men, 3)//These three are all different types of elements, but they implement interface the same interface X[0], x[1], x[2] = Paul, Sam, Mike for _, Value: = Range x{value. Sayhi ()}}

From the code above, you will find that interface is a collection of abstract methods that must be implemented by other non-interface types, not self-fulfilling, and go through interface to achieve duck-typing: "When you see a bird walking up like a duck, Swimming up like a duck and barking like a duck, the bird can be called a duck.

Empty interface

Empty interface (interface{}) does not contain any method, and because of this, all types implement an empty interface. The null interface does not have any effect on the description (because it does not contain any method), but the null interface is useful when we need to store any type of numeric value, because it can store any type of value. It is somewhat similar to the void* type of C language.

// 定义a为空接口var a interface{}var i int = 5s := "Hello world"// a可以存储任意类型的数值a = ia = s

A function takes interface{} as a parameter, then he can accept any type of value as a parameter, and if a function returns interface{}, it can return any type of value. is not very useful ah!

interface function Parameters

The interface variable can hold any object that implements the interface type, which gives us some extra thought about how to write the function (including method), whether we can define the interface parameter and let the function accept various types of arguments.

As an example: FMT. PRINTLN is a common function of ours, but do you notice that it can accept any type of data? Open the FMT source file and you will see a definition like this:

type Stringer interface {     String() string}

That is, any type that implements the string method can be fmt.println called as a parameter, let's try

package mainimport (    "fmt"    "strconv")type Human struct {    name string    age int    phone string}// 通过这个方法 Human 实现了 fmt.Stringerfunc (h Human) String() string {    return "❰"+h.name+" - "+strconv.Itoa(h.age)+" years -  ✆ " +h.phone+"❱"}func main() {    Bob := Human{"Bob", 39, "000-7777-XXX"}    fmt.Println("This Human is : ", Bob)}

Now let's review the previous box example, and you'll see that the color structure also defines a method:string. In fact this is also achieved by the FMT. Stringer this interface, that is, if you need a type that can be output by the FMT package in a special format, you have to implement the Stringer interface. If this interface is not implemented, the FMT will be output in the default manner.

//实现同样的功能fmt.Println("The biggest one is", boxes.BiggestsColor().String())fmt.Println("The biggest one is", boxes.BiggestsColor())

Note: An object that implements the error interface (that is, an object that implements the error () string), the error () method is called when using the FMT output, so you do not have to define the string () method.

Types of interface variable storage

We know that interface variables can store any type of value (this type implements the interface). So how do we know what type of object is actually stored in this variable? There are two methods that are commonly used today:

Comma-ok Assertion

The go language has a syntax that can directly determine if it is a variable of that type: value, OK = element. (t) where value is the value of the variable, OK is a bool type, element is a interface variable, and T is the type of assertion.

If the element does store a value of type T, then OK returns true, otherwise false is returned.

Let's take an example to get a deeper understanding.

 package mainimport ("FMT" "StrConv") type Element interface{}type List [] ElementType The person struct {name String age int}//defines a string method that implements the FMT. Stringerfunc (P person) string () string {return ' (name: "+ p.name +"-Age: "+strconv.    Itoa (P.age) + "years)"}func main () {list: = Make (list, 3) list[0] = 1//an int list[1] = "Hello"//A String LIST[2] = person{"Dennis", for index, element: = Range List {if value, OK: = element. ( int); OK {fmt. Printf ("list[%d" is a int and its value is%d\n ", index, value)} else if value, OK: = element. (string); OK {fmt. Printf ("list[%d" is a string and its value is%s\n ", index, value)} else if value, OK: = element. (person); OK {fmt. Printf ("list[%d" is a person and its value is%s\n ", index, value)} else {fmt. Println ("list[%d" is of a different type ", Index)}}}  

Is it very simple, at the same time you notice the multiple if inside, remember when I described the process earlier, the if inside allow initialization of variables.

Perhaps you have noticed that the more types we assert, the more if else, the more you can get the switch that is described below.

Switch test

The best explanation is the code example, now let's rewrite the implementation above

 package mainimport ("FMT" "StrConv") type Element interface{}type List [] ElementType person struct {Name string age int}//print func (P person) string () string {return ' (name: "+ p.name +"-Age: " +strconv. Itoa (P.age) + "years)"}func main () {list: = Make (list, 3) list[0] = 1//an int list[1] = "Hello"//a string L IST[2] = person{"Dennis", +} for index, element: = range list{switch value: = element. ( Type) {case int:fmt. Printf ("list[%d" is a int and its value are%d\n ", index, value) case string:fmt. Printf ("list[%d" is a string and its value are%s\n ", index, value) case person:fmt. Printf ("list[%d" is a person and its value is%s\n ", index, value) default:fmt. Println ("list[%d" is of a different type ", Index)}}}  

Here's one thing to emphasize: element. The (type) syntax cannot be used in any logic outside of switch, and if you want to judge a type outside of switch, use COMMA-OK.

Embedding interface

What really appeals to go is its built-in logic syntax, just like the anonymous fields we learn when we learn structs, and how elegant it is to introduce the same logic into interface, which is not more perfect. If a Interface1 is an embedded field of Interface2, then Interface2 implicitly contains the method inside the Interface1.

We can see that the source package container/heap has such a definition

type Interface interface {    sort.Interface //嵌入字段sort.Interface    Push(x interface{}) //a Push method to push elements into the heap    Pop() interface{} //a Pop elements that pops elements from the heap}

We see sort. Interface is actually an embedded field that puts the sort. All method of interface is included in the implicit. This is the following three methods:

type Interface interface {    // Len is the number of elements in the collection.    Len() int    // Less returns whether the element with index i should sort    // before the element with index j.    Less(i, j int) bool    // Swap swaps the elements with indexes i and j.    Swap(i, j int)}

Another example is IO under IO packet. Readwriter, which contains the reader and writer two interface below the IO package:

// io.ReadWritertype ReadWriter interface {    Reader    Writer}

Reflection

The go language implements reflection, so-called reflection is the ability to check the state of the program at run time. The package we usually use is a reflect bag. How to use the reflect package, the official article explains in detail the reflect package implementation principle, laws of reflection

The use of reflect is generally divided into three steps, the following brief explanation: to go to reflect is a type of value (these values are implemented in the empty interface), first need to convert it to reflect object (reflect. Type or reflect.value, calling different functions depending on the situation). The two ways to get these are:

t := reflect.TypeOf(i)    //得到类型的元数据,通过t我们能获取类型定义里面的所有元素v := reflect.ValueOf(i)   //得到实际的值,通过v我们获取存储在里面的值,还可以去改变值

After converting to a reflect object, we can do something, that is, convert the reflect object to the corresponding value, for example

tag := t.Elem().Field(0).Tag  //获取定义在struct里面的标签name := v.Elem().Field(0).String()  //获取存储在第一个字段里面的值

Gets the reflected value to return the corresponding type and value

var x float64 = 3.4v := reflect.ValueOf(x)fmt.Println("type:", v.Type())fmt.Println("kind is float64:", v.Kind() == reflect.Float64)fmt.Println("value:", v.Float())

Finally, the reflection of the words, then the reflection of the field must be modifiable, we have learned in front of the value and the reference, this is the same truth. The reflected field must be read-write, meaning that if the following is written, an error occurs

var x float64 = 3.4v := reflect.ValueOf(x)v.SetFloat(7.1)

If you want to modify the corresponding value, you must write this

var x float64 = 3.4p := reflect.ValueOf(&x)v := p.Elem()v.SetFloat(7.1)

ValueOf obtained is a copy, and its modification has no effect on the original data. If you want to modify the original value, you need to use a pointer. Then use P. Elem will be able to obtain objects that can be modified.

To deal with structs,

Like this, too.

type T struct {A intB string}func main() {a := 1fmt.Println(reflect.TypeOf(a))fmt.Println(reflect.ValueOf(a))t := T{23, "skidoo"}fmt.Println(reflect.TypeOf(t))fmt.Println(reflect.ValueOf(t))s := reflect.ValueOf(&t).Elem() //ValueOf.Elem必须要指针类型,否则会panictypeOfT := s.Type()for i := 0; i < s.NumField(); i++ {f := s.Field(i)fmt.Printf("%d: %s %s = %v\n", i,typeOfT.Field(i).Name, f.Type(), f.Interface())}}

The output is as follows:

Int
1
Main. T
{Skidoo}
0:a int =
1:b string = Skidoo

The object can be modified by Elem, and then filed to get the corresponding 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.