- Jordan Oreilli对接口的定义:接口是两件事物,接口是一组方法,也是一种类型。
- Russ Coxx在《关于接口内部结构的精彩文章》中解释到接口会由两个指针组成,其一是指向【类型】相关信息的指针,其二是指向【数据】相关的信息的指针。
Go语言提供interface{}
表示空接口类型
- 空接口可用于保存任何数据
- 空接口作为有用的参数可使用任意类型
- 使用空接口作为参数的方法可接收任何类型
空接口表示没有任何方法的接口,也就是所没有任何方法需要实现。由于所有类型都至少实现零个方法,因此会自动满足该接口,所以任何类型都满足空接口。由于空接口是隐式实现的,每种类型都满足空接口锲约,因此任何变量都可以赋值给interface{}
类型的变量。
Go语言中任何对象都可以实现空接口,任何对象也都可以保存在空接口实例变量中。
空接口
空接口是一种接口,因此是一种指针类型的数据类型,虽然并不严谨,但它确实保存了两个指针,一个是对象的类型iTable
,另一个是对象的值。因此任意类型的对象都能赋值给空接口实例。
package main
import (
"fmt"
)
func main () {
var any interface{}
any = 1
fmt.Printf("any = %v, type = %T\n", any, any)//any = 1, type = int
any = "hello"
fmt.Printf("any = %v, type = %T\n", any, any)//any = hello, type = string
}
由于空接口拥有两个指针,内存布局上两个指针会占用两个机器字长。
为什么将切片中的数据拷贝到空接口切片中时会报错?
package main
import (
"fmt"
)
func main () {
slice := []int{1, 2, 3, 4}
var newSlice []int
newSlice = slice
fmt.Printf("slice = %v, newSlice = %v\n", slice, newSlice)//slice = [1 2 3 4], newSlice = [1 2 3 4]
var any []interface{}
any = slice//cannot use slice (type []int) as type []interface {} in assignment
}
因为每个空接口的内存布局都会占用两个机器字长的内容,对于长度为N的空接口切片而言,它的每个元素都是以2机器字长为单位的连续空间,因此会总共会占用2N个机器字长的空间。然后普通的切片,比如[]int
它的每个元素都是int
类型的,由于int
类型的内存布局和空接口不同。另外这些对象的内存布局在编译期就已经确定好了,所以不能直接将不同内存布局的数据结构进行拷贝。
若想要实现拷贝则需使用for-range
方式,将普通切片中的每个元素都赋值给空接口切片中的空接口元素形成一个个的空接口实例。
package main
import (
"fmt"
)
func main () {
slice := []int{1, 2, 3, 4}
var newSlice []int
newSlice = slice
fmt.Printf("slice = %v, newSlice = %v\n", slice, newSlice)//slice = [1 2 3 4], newSlice = [1 2 3 4]
var any []interface{}
for _,v := range slice{
any = append(any, v)
}
fmt.Printf("any = %v, type = %T\n", any, any)//any = [1 2 3 4], type = []interface {}
}
空接口切片中每个空接口实例都会指向更加底层的各个数据对象
空接口类型
使用空接口表示任意数据类型,类似于Java中的Object
。因此空接口可以存储任意类型的值,类似于C语言中的void *
类型。
空接口类型让Go语言像其它动态语言一样,在数据结构中存储任意类型的数据。
定义
type InterfaceName interface{}
可直接使用interface{}
作为空接口类型以表示空接口
声明
var i interface{}
func fn(data interface{}){
}
空接口数据类型
可定义空接口类型的array
、slice
、map
、struct
等,用来存放任意类型的对象,因为任何类型都实现了空接口。
例如:创建空接口类型的切片
package main
import (
"fmt"
)
func main () {
any := make([]interface{}, 4)
any[0] = 1
any[1] = "admin"
any[2] = []int{1, 2, 3}
for _,v := range any{
fmt.Printf("type = %T, value = %v\n", v, v)
}
}
type = int, value = 1
type = string, value = admin
type = []int, value = [1 2 3]
type = , value =
转化
为了将一个接口变量转换为一个显式的类型,Go提供了.(TYPE)
使用空接口与转化实现断言
package main
import (
"fmt"
)
func assign(arg interface{}){
switch t := arg.(type){
case string:
fmt.Printf("content = %s, type = %T\n", t, t)
case int:
fmt.Printf("content = %d, type = %T\n", t, t)
case bool:
fmt.Printf("content = %v, type = %T\n", t, t)
}
}
func main () {
assign(1)
}