35. Three "unspoken rules" about interfaces in Go

Posted Jun 16, 20204 min read

Hi, everyone, this is Ming Ge.

During my time learning Golang, I wrote detailed study notes and put them in my personal WeChat public account "Go Programming Time". For Go language, I am also a beginner, so what I write should be more suitable If you are new to classmates, if you are just learning the Go language, don t be concerned about it, learn together and grow together.

My online blog: http://golang.iswbm.com
My Github:github.com/iswbm/GolangCodingTime

1. Restrictions on method calls

An interface is a fixed set of methods. Due to the limitations of static types, interface variables can sometimes only call certain methods.

Please see the code below

package main

import "fmt"

type Phone interface {
    call()
}

type iPhone struct {
    name string
}

func(phone iPhone)call() {
    fmt.Println("Hello, iPhone.")
}

func(phone iPhone)send_wechat() {
    fmt.Println("Hello, Wechat.")
}

func main() {
    var phone Phone
    phone = iPhone{name:"ming's iphone"}
    phone.call()
    phone.send_wechat()
}

I defined a Phone interface, and only required to implement the call method, that is, as long as the device that can make a call is a phone(it seems like a useless nonsense).

Then define an iPhone structure, the structure receives two methods, one is to make a call(call function), the other is to send WeChat(send_wechat function).

The last step is the key. We define a phone object of the Phone interface type. The content of this object is the iPhone structure. Then we call the call method of the object, everything is normal.

But when you call the phone.send_wechat method, the program will report an error, prompting us that the Phone type method does not have a send_wechat field or method.

# command-line-arguments
./demo.go:30:10:phone.send_wechat undefined(type Phone has no field or method send_wechat)

The reason is also obvious, because our phone object is explicitly declared as the Phone interface type, so the methods called by the phone will be restricted by this interface.

So how to make phone call send_wechat method?

The answer is that it can be declared as the Phone interface type, but it should be clear that the phone object actually implements the Phone interface implicitly, so that the method call will not be constrained by the interface type.

Modify the main method as follows

func main() {
    phone := iPhone{name:"ming's iphone"}
    phone.call()
    phone.send_wechat()
}

After running, everything is normal and no error is reported.

Hello, iPhone.
Hello, Wechat.

2. Implicit conversion when calling a function

Function calls in Go are all passed by value, and variables are type-converted before method calls.

For example, the following code

import(
    "fmt"

)

func printType(i interface{}) {

    switch i.(type) {
    case int:
        fmt.Println("The parameter type is int")
    case string:
        fmt.Println("The type of the parameter is string")
    }
}

func main() {
    a := 10
    printType(a)
}

If you run it, you will find everything is normal

The type of the parameter is int

But if you move the content inside the function to the outside

package main

import "fmt"


func main() {
    a := 10

    switch a.(type) {
    case int:
        fmt.Println("The parameter type is int")
    case string:
        fmt.Println("The type of the parameter is string")
    }
}

There will be unexpected results, and actually reported an error.

# command-line-arguments
./demo.go:9:5:cannot type switch on non-interface value a(type int)

This operation will make a newcomer confused, and the logic of the code is the same. Why does one not report an error, and one will report an error?

The reason is actually very simple.

When a function interface interface{} is an empty interface type, we say that it can accept any type of parameter(called no tricks on the rivers and lakes).

When you use this way of writing, Go will silently do one thing for us, which is to implicitly convert the type of the parameter value passed into the function(note:function calls in Go language are passed by value) to interface {} Types of.

How to perform interface type conversion

After understanding the implicit conversion of the interface type in the function above, you may start to have doubts in my mind. Can I use type assertion only by a function that receives an empty interface type?

The answer is of course No.

If you want to manually convert it, you can convert the static type of variable a to interface{} and assign it to b(the static type of a is still int, and the static type of b is interface{})

var a int = 25
b := interface{}(a)

After knowing the method, modify the code as follows:

package main

import "fmt"


func main() {
    a := 10

    switch interface{}(a).(type) {
    case int:
        fmt.Println("The parameter type is int")
    case string:
        fmt.Println("The type of the parameter is string")
    }
}

After running, everything is normal.

The type of the parameter is int

3. Implicit conversions in type assertions

As we know above, only objects whose static type is interface type can be type asserted.

When the type assertion is completed, it will return an object whose static type is the type you assert. That is to say, when we use the type assertion, Go will actually perform an implicit type conversion for us by default.

The verification method is also very simple. After using the type assertion once, use the type assertion again on the returned object. Goland will immediately prompt us that the new object b is not an interface type object, and type assertion is not allowed.