Empty interface

define

An empty interface is a special form of interface type. Normal interfaces have methods, but empty interfaces do not define any method ports. Therefore, we can say that all types implement at least an empty interface.

type test interface {
}
Copy the code

Each interface contains two properties, a value and a type.

Var I interface {} FMT. Printf (" type: % T - value: % v \ n ", I, I) / / type: < nil > - value: < nil >Copy the code

So both of these are nil for an empty interface

Usage scenarios

First, we usually declare an instance directly using interface{} as a type, and this instance can hold any type of value.

Func main() {var I interface{} I = 100 ftt.println (I) //100 I = "yif" ftt.println (I) //yif I = 3.14 ftt.println (I) //3.14 I = false fmt.println (I)Copy the code

Second, if you want your function to accept any type of value, you can also use a null interface. The following codes are printed normally:

Func main() {I := 100 s := "yif" f := 3.14 test(I) test(s) test(f)} func test(I interface{}) {ftt.println (I)}Copy the code

It’s a little tricky to write above, but you can use mutable functions. As follows:

Func main() {I := 100 s := "yif" f := 3.14 test(I, s, f)} func main() {I := 100 s := "yif" f := 3.14 test(I, s, f)} For k, v := range res {FMT.Println(k, v)}}Copy the code

Results:

D: workspace\go\ SRC \test>go run main.go [100 yif 3.14] 0 100 1 yif 2 3.14Copy the code

Third, you can also define an array that accepts any type of array, slice, map, or strcut. For example, define a slice here

func main() { sli := make([]interface{}, 4) sli[0] = 100 sli[1] = "yif" sli[2] = []int{1, 2, 3} sli[3] = [...] int{5, 6, 7} fmt.Println(sli) for k, v := range sli { fmt.Println(k, v) } }Copy the code

Results:

D:\workspace\go\src\test>go run main.go
[100 yif [1 2 3] [5 6 7]]
0 100
1 yif
2 [1 2 3]
3 [5 6 7] 
Copy the code

Empty interface several pits to note

** First, an empty interface can carry any value, but it does not mean that any type can carry a value of an empty interface type

A null interface type can hold any value, or it can fetch the original value from the null interface.

However, if you assign an object of an empty interface type to an object of fixed type (such as int, string, etc.), an error will be reported.

var i interface{} = 100
var t int = i // cannot use i (type interface {}) as type int in assignment: need type assertion
Copy the code

But if you use short variable declarations, that’s fine:

var i interface{} = 100
t := i
fmt.Println(t) //100
Copy the code

Because the compiler does the initialization by deriving the type of the variable from the value to the right of the equals sign.

** The object can no longer be sliced when the empty interface carries the array and slice

sli := []int{1, 2, 3, 4}
var i interface{}
i = sli
fmt.Println(i[1:2]) //cannot slice i (type interface {})
Copy the code

Types of assertions

Type Assertion is an operation used on an interface value to check whether the value held by an interface Type variable implements the desired interface or specific Type

Type assertion, which can only be asserted on objects with statically typed empty interfaces (interface{}), otherwise an error will be thrown

Two syntax for type assertion in Go

The first syntactic format for type assertions in Go is as follows:

t := i.(T)
Copy the code

This expression can assert that an interface object (I) is not nil, and that the interface object (I) stores a value of type T. If the assertion succeeds, the value will be returned to T, and if the assertion fails, panic will occur.

func main() {
	var i interface{} = 100
	t := i.(int)
	fmt.Println(t) //100
	
	fmt.Println("------------------------------------")

	s := i.(string)
	fmt.Println(s)
}
Copy the code

Result [failed to execute the second assertion and triggered panic] :

D:\workspace\go\src\test>go run main.go
100
------------------------------------
panic: interface conversion: interface {} is int, not string

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:32 +0x10e
exit status 2 
Copy the code

If the interface value being asserted is nil, let’s see if panic is triggered as expected

var i interface{}
var _ = i.(interface{})
Copy the code

Results:

D:\workspace\go\src\test>go run main.go
panic: interface conversion: interface is nil, not interface {}

goroutine 1 [running]:
main.main()
        D:/workspace/go/src/test/main.go:27 +0x34
exit status 2 
Copy the code

Another syntax format for type assertions in the Go language is as follows:

t, ok:= i.(T)
Copy the code

As above, this expression can also assert that an interface object (I) is not nil, and that the interface object (I) stores a value of type T. If the assertion succeeds, the type is returned to T, and ok is true, indicating success.

If the interface value is of a type other than T, the assertion fails, but unlike the first expression, this does not trigger panic. Instead, it sets ok to false, indicating that the assertion fails, where T is zero for T.

Func main () {var I interface {} = 10 t1, ok: i. = (int), FMT) Printf (" % d - % t \ n ", t1, ok) FMT. Println (" = = = = = separation line 1 = = = = = ") t2, Ok: i. = (string) FMT) Printf (" % s \ n - % t, "t2, ok) FMT. Println (" = = = = = = = = = = separation line 2") interface var k {} / / nil t3, K. (interface ok: = {}) FMT. Println (t3, "-", ok) FMT. Println (" = = = = = separation line 3 = = = = = ") k = 10 t4, ok := k.(interface{}) fmt.Printf("%d-%t\n", t4, ok) t5, ok := k.(int) fmt.Printf("%d-%t\n", t5, ok) }Copy the code

The second assertion failed, but did not trigger panic:

D: \ workspace \ go \ SRC \ test > go run. Main go 10 - true = = = = = separation line 1 = = = = = = = = = = - false separation line 2 = = = = = < nil > - false = = = = = separation line 3 = = = = = 10-true 10-trueCopy the code

The output of the second assertion before -false does not output any value of t2, but because the assertion failed, t2 gets a string of zero, which is zero length, so you can’t see its output.

Type assertions work with the Switch

If you need to distinguish between multiple types, you can use type Switch assertions.

Func main() {test(100) test("yif") test(3.14) var I interface{} //nil test(I) test(nil)} func test(I interface{}) { Switch r := I.(type) {case int: FMT.Println(r, "is int ") case String: FMT.Println(r," is string ") case nil: Println(r, "nil") default: Println(" no result! ") )}}Copy the code

Results:

D: workspace\go\ SRC \test>go run main. <nil> is nil. <nil> is nilCopy the code