empty interface
definition
Empty interface is a special form of interface type. Ordinary interfaces have methods, but empty interfaces do not define any method ports. Therefore, we can say that all types implement at least empty interfaces.
type test interface {
}
复制代码
Each interface contains two properties, one is the value and one is the type.
var i interface{}
fmt.Printf("类型:%T----值:%v\n", i, i) //类型:<nil>----值:<nil>
复制代码
It can be seen that for empty interfaces, both are nil
scenes to be used
First , we usually declare an instance directly using interface{}
as a type, and this instance can hold values of any type.
func main() {
var i interface{}
i = 100
fmt.Println(i) //100
i = "yif"
fmt.Println(i) //yif
i = 3.14
fmt.Println(i) //3.14
i = false
fmt.Println(i) //false
}
复制代码
Second , if you want your function to accept any type of value, you can also use an empty interface. The following code prints normally:
func main() {
i := 100
s := "yif"
f := 3.14
test(i)
test(s)
test(f)
}
func test(i interface{}) {
fmt.Println(i)
}
复制代码
The above way of writing is a bit cumbersome, you can use variadic functions. as follows:
func main() {
i := 100
s := "yif"
f := 3.14
test(i, s, f)
}
func test(res ...interface{}) {
fmt.Println(res) //res是切片
for k, v := range res {
fmt.Println(k, v)
}
}
复制代码
result:
D:\workspace\go\src\test>go run main.go
[100 yif 3.14]
0 100
1 yif
2 3.14
复制代码
Third , you also define an array, slice, map, strcut that can receive any type, 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)
}
}
复制代码
result:
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]
复制代码
Several pits to pay attention to in the empty interface
**First,** an empty interface can carry any value, but it does not mean that any type can accept the value of the empty interface type
An empty interface type can hold any value, and can also retrieve the original value from the empty interface.
But if you assign an object of empty interface type to an object of a 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
复制代码
But you can use short variable declarations:
var i interface{} = 100
t := i
fmt.Println(t) //100
复制代码
Because the compiler will deduce the type of the variable based on the value on the right side of the equal sign to complete the initialization.
**Second:** When the empty interface carries arrays and slices, the object can no longer be sliced
sli := []int{1, 2, 3, 4}
var i interface{}
i = sli
fmt.Println(i[1:2]) //cannot slice i (type interface {})
复制代码
type assertion
Type Assertion is an operation used on interface values to check whether the value held by an interface type variable implements the expected interface or concrete type
Type assertion, only objects whose static type is an empty interface (interface{}) can be asserted, otherwise an error will be thrown
Two syntaxes for type assertion in Go
The first syntax for type assertions in Go is as follows:
t := i.(T)
复制代码
This expression can assert that an interface object (i) is not nil, and the type of the value stored in the interface object (i) is T. If the assertion succeeds, it will return the value to t, and if the assertion fails, panic will be triggered.
func main() {
var i interface{} = 100
t := i.(int)
fmt.Println(t) //100
fmt.Println("------------------------------------")
s := i.(string)
fmt.Println(s)
}
复制代码
Result [Failed when executing 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
复制代码
如果要断言的接口值是 nil,那我们来看看也是不是也如预期一样会触发panic
var i interface{}
var _ = i.(interface{})
复制代码
结果:
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
复制代码
在Go语言中类型断言的另一种语法格式如下:
t, ok:= i.(T)
复制代码
和上面一样,这个表达式也是可以断言一个接口对象(i)里不是 nil,并且接口对象(i)存储的值的类型是 T,如果断言成功,就会返回其类型给 t,并且此时 ok 的值 为 true,表示断言成功。
如果接口值的类型,并不是我们所断言的 T,就会断言失败,但和第一种表达式不同的事,这个不会触发 panic,而是将 ok 的值设为 false ,表示断言失败,此时t 为 T 的零值。
func main() {
var i interface{} = 10
t1, ok := i.(int)
fmt.Printf("%d-%t\n", t1, ok)
fmt.Println("=====分隔线1=====")
t2, ok := i.(string)
fmt.Printf("%s-%t\n", t2, ok)
fmt.Println("=====分隔线2=====")
var k interface{} // nil
t3, ok := k.(interface{})
fmt.Println(t3, "-", ok)
fmt.Println("=====分隔线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)
}
复制代码
结果【运行后输出如下,可以发现在执行第二次断言的时候,虽然失败了,但并没有触发了 panic】:
D:\workspace\go\src\test>go run main.go
10-true
=====分隔线1=====
-false
=====分隔线2=====
<nil> - false
=====分隔线3=====
10-true
10-true
复制代码
上面这段输出,你要注意的是第二个断言的输出在-false
之前并不是有没有输出任何 t2 的值,而是由于断言失败,所以 t2 得到的是 string 的零值也是 ""
,它是零长度的,所以你看不到其输出。
类型断言配合 switch 使用
如果需要区分多种类型,可以使用 type switch 断言。
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, "是int型")
case string:
fmt.Println(r, "是字符串")
case nil:
fmt.Println(r, "是nil")
default:
fmt.Println("没有结果!")
}
}
复制代码
结果:
D:\workspace\go\src\test>go run main.go
100 是int型
yif 是字符串
没有结果!
<nil> 是nil
<nil> 是nil
复制代码