define
-
Interface is a collection of defined method signatures that specify the behavior of an object. If an object implements the behavior defined by the set of methods in Interface, it implements the Interface.
-
These methods can be implemented by different objects in different places, and these implementations can have different behaviors;
-
The main job of an interface is simply to provide method name signatures, input parameters, and return types. Methods are ultimately implemented by concrete objects, such as structs;
-
Interface initializes to nil;
-
The type keyword is used for this declaration, interface represents the type, and curly braces define the set of method signatures for the interface.
type Animal interface { Bark() string Walk() string } Copy the code
As follows, Dog implements the Animal interface, so you can use an instance of Animal to receive an instance of Dog. You must implement both Bark() and Walk(), otherwise you are not implementing the Animal interface.
type Dog struct { name string } func (dog Dog) Bark() string { fmt.Println(dog.name + ":wan wan wan!") return "wan wan wan" } func (dog Dog) Walk() string { fmt.Println(dog.name + ":walk to park!") return "walk to park" } func main() { var animal Animal fmt.Println("animal value is:", animal) //animal value is: <nil> fmt.Printf("animal type is: %T\n", animal) //animal type is: <nil> animal = Dog{"Prosperous wealth."} animal.Bark() // Bark :wan Wan wan! Animal.Walk() // Walk to park! fmt.Println("animal value is:", animal) //animal value is: {FMT.Printf("animal type is: %T\n", animal) //animal type is: main.Dog } Copy the code
nil interface
In the example above, we print the animal we just defined:
- The value is nil
- The type also is nil
Interface values with nil underlying values:
- I’m just going to say that interfaces that aren’t assigned are nil interface, value and type are nil
- As long as you assign, even if you assign a value of type nil, it’s no longer a nil interface
type I interface {
Hello()
}
type S []int
func (i S) Hello() {
fmt.Println("hello")
}
func main() {
var i I
fmt.Printf("1:i Type:%T\n", i)
fmt.Printf("2:i Value:%v\n", i)
var s S
if s == nil {
fmt.Printf("3:s Value%v\n", s)
fmt.Printf("4:s Type is %T\n", s)
}
i = s
if i == nil {
fmt.Println("5:i is nil")}else {
fmt.Printf("6:i Type:%T\n", i)
fmt.Printf("7:i Value:%v\n", i)
}
}
Copy the code
output:
1:i Type:<nil>
2:i Value:<nil>
3:s Value[]
4:s Type is main.S
6:i Type:main.S
7:i Value:[]
Copy the code
According to the result, the initialized variable I is a nil interface. When I is assigned to the variable S with a value of nil, I is no longer nil interface. Those of you who are careful will notice a detail in line 3 of the output
3:s Value[]
Copy the code
The value of s is nil, but the output is a []. This is because FMT uses reflection to determine what to print. Since S is of type slice, FMT is represented by [].
empty interface
Go allows interfaces without any methods. This type of interface is called an Empty Interface. All types implement empty Interface, because any type implements at least 0 methods. A typical application scenario is the FMT package Println method, which can receive various types of data and output to the console, thanks to interface{}. Let’s take a look at the case:
func Print(i interface{}) {
fmt.Println(i)
}
func main() {
var i interface{}
i = "hello"Print(I) I = 100 Print(I) I = 1.29 Print(I)}Copy the code
Print (interface{}) accepts string,int,float, etc. Slice of type interface{} can accept any type of slice, although interface{} can accept any type of slice. The following code will trigger a Panic error,
var dataSlice []int = foo()
var interfaceSlice []interface{} = dataSlice
// cannot use dataSlice (type []int) as type []interface { } in assignment
Copy the code
For specific reasons, the official website wiki(github.com/golang/go/w…) Errors are caused by two things:
- []interface{} is not an interface, it is a slice, only the elements in the slice are interfaces
- The memory sizeof the []interface{} type is determined at compile time (N*2), while the sizeof the other slice types is N* sizeof(MyType), so it is not quick to assign the type []MyType to []interface{}.
Determine which type is stored in the interface variable
An interface can be implemented with multiple types. Sometimes we need to distinguish which type of value the interface variable stores. Type assertions provide access to the underlying concrete value of an interface value
t := i.(T)
Copy the code
This statement asserts that the interface value I holds the concrete type T and assigns the base value of T to the variable T. If I stores a value other than type T, a panic error will be triggered. To avoid panic errors, you can do the following for assertion checking
t, ok := i.(T)
Copy the code
Assertion succeeds, ok has a value of true, t has a zero value of type T for assertion failure, and no panic error occurs.
func main() {
var i interface{}
i = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
i = 100
t, ok := i.(int)
fmt.Println(t, ok)
t2 := i.(string) //panic
fmt.Println(t2)
}
Copy the code
Type switch
Another convenient way to determine the specific type of interface variable is to use the switch statement. As follows:
func Print(i interface{}) {
switch i.(type) {
case string:
fmt.Printf("type is string,value is:%v\n", i.(string))
case float64:
fmt.Printf("type is float32,value is:%v\n", i.(float64))
case int:
fmt.Printf("type is int,value is:%v\n", i.(int))
}
}
func main() {
var i interface{}
i = "hello"Print(I) I = 100 Print(I) I = 1.29 Print(I)}Copy the code
The flexible and efficient interface dynamic typing enables the Go language to safely and flexibly convert between different compatible types while maintaining the safety and efficiency of strong static typing
Originally posted on my Github
reference
Golang print nil
InterfaceSlice