This is the 19th article in the “Learn to Go” series
What is an interface
In some object-oriented programming languages, such as Java, PHP, etc., interfaces define the behavior of an object and only specify what the object should do. The exact implementation of the behavior depends on the object.
In Go, an interface is a collection of methods, but it contains no implementation of the method, is abstract, and cannot contain variables. When a type T provides definitions of all methods in the interface, T is said to implement the interface. Interfaces specify what methods a type should have, and types determine how those methods are implemented.
Interface declaration
An interface is declared like a structure, using a type alias and requiring the keyword interface. The syntax is as follows:
type Name interface {
Method1(param_list) return_type
Method2(param_list) return_type
...
}
Copy the code
Actually define an interface:
type Shape interface {
Area() float32
}
Copy the code
The above code defines the interface type Shape, which contains a method Area() that takes no arguments and returns float32. Any type T that implements the method Area() is said to implement Shape.
type Shape interface {
Area() float32
}
func main(a) {
var s Shape
fmt.Println("value of s is", s)
fmt.Printf("type of s is %T\n", s)
}
Copy the code
Output:
value of s is <nil>
type of s is <nil>
Copy the code
In the above code, since the interface is a type, we can create a Shape variable s. Are you wondering why s is of type nil? Let’s move on to the next section!
Interface type value
Static and dynamic types
A variable whose type is specified at declaration time and cannot be changed is called a static type. The static type of an interface type is the interface itself. The interface does not have static values; it points to dynamic values. An interface type variable holds the value of the type that implements the interface. This value is the dynamic value of the interface, and the type that implements the interface is the dynamic type of the interface.
type Iname interface {
Mname()
}
type St1 struct {}
func (St1) Mname(a) {}
type St2 struct {}
func (St2) Mname(a) {}
func main(a) {
var i Iname = St1{}
fmt.Printf("type is %T\n",i)
fmt.Printf("value is %v\n",i)
i = St2{}
fmt.Printf("type is %T\n",i)
fmt.Printf("value is %v\n",i)
}
Copy the code
Output:
type is main.St1
value is {}
type is main.St2
value is {}
Copy the code
The static type of variable I is Iname and cannot be changed. The dynamic type is not fixed. After the first assignment, the dynamic type of I is St1. After the second assignment, the dynamic type of I is St2.
Sometimes, the dynamic type of an interface is called a concrete type, and when we access the interface type, we return the type of the underlying dynamic value.
Nil interface values
Let’s look at an example:
type Iname interface {
Mname()
}
type St struct {}
func (St) Mname(a) {}
func main(a) {
var t *St
if t == nil {
fmt.Println("t is nil")}else {
fmt.Println("t is not nil")}var i Iname = t
fmt.Printf("%T\n", i)
if i == nil {
fmt.Println("i is nil")}else {
fmt.Println("i is not nil")
}
fmt.Printf("i is nil pointer:%v",i == (*St)(nil))}Copy the code
Output:
t is nil
*main.St
i is not nil
i is nil pointer:true
Copy the code
Isn’t it surprising that we assign the value of variable I to nil, but I is not nil. Let’s see what happened!
Dynamic types, as discussed above, are the values that are actually allocated. Remember one thing: interface type values are nil if and only if both dynamic values and dynamic types are nil. In the code above, after assigning to the variable I, the dynamic value of I is nil, but the dynamic type is *St, and I is an NILL pointer, so the equality condition is not true.
Take a look at the Go language specification:
var x interface{} // x is nil and has static type interface{}
var v *T // v has value nil, static type *T
x = 42 // x has value 42 and dynamic type int
x = v // x has value (*T)(nil) and dynamic type *T
Copy the code
The dynamic type of s is nil when var s Shape is declared. The dynamic type of S is nil.
Implementing an interface
See the sample:
type Shape interface {
Area() float32
}
type Rect struct {
width float32
height float32
}
func (r Rect) Area(a) float32 {
return r.width * r.height
}
func main(a) {
var s Shape
s = Rect{5.0.4.0}
r := Rect{5.0.4.0}
fmt.Printf("type of s is %T\n", s)
fmt.Printf("value of s is %v\n", s)
fmt.Println("area of rectange s", s.Area())
fmt.Println("s == r is", s == r)
}
Copy the code
Output:
type of s is main.Rect
value of s is {5 4}
area of rectange s 20
s == r is true
Copy the code
The above code creates the interface Shape, structure Rect, and method Area(). Since Rect implements all, though only one, of the methods defined by the interface, Rect implements the interface Shape.
In the main function, we create a variable s of interface type, nil, and initialize it with a Rect structure, which is valid because the Rect structure implements the interface. After the assignment, the dynamic type of S becomes Rect, and the dynamic value is the structure value {5.0,4.0}.
The Area() method can be called directly using the. Syntax because the concrete type of S is Rect, and Rect implements the Area() method.
Empty interface
An interface that does not contain any methods is called an empty interface, such as interface{}. Because an empty interface does not contain any methods, any type implements an empty interface by default.
For example, the Println() function in the FMT package can accept multiple types of values, such as int, string, array, and so on. Why? Because its parameters are interface types and can accept values of any type.
func Println(a ...interface{}) (n int, err error) {}
Copy the code
Let’s look at an example:
type MyString string
type Rect struct {
width float32
height float32
}
func explain(i interface{}) {
fmt.Printf("type of s is %T\n", i)
fmt.Printf("value of s is %v\n\n", i)
}
func main(a) {
ms := MyString("Seekload")
r := Rect{5.0.4.0}
explain(ms)
explain(r)
}
Copy the code
Output:
type of s is main.MyString
value of s is Seekload
type of s is main.Rect
value of s is {5 4}
Copy the code
The above code creates custom string types MyString, struct Rect, and explain() functions. The explain() function takes an empty interface parameter, so it can accept any type of value.
That’s all for the first part of the article on interface use, and I will write another article to tell you the rest. Stay tuned!
Original article, if need to be reproduced, please indicate the source! Check out “Golang is coming” or go to seekload.net for more great articles.
The public account “Golang is coming” has prepared a mystery learning gift package for you, and the background replies [ebook] to get it!