空接口
空接口是指沒(méi)有定義任何接口方法的接口。沒(méi)有定義任何接口方法,意味著Go中的任意對(duì)象都可以實(shí)現(xiàn)空接口(因?yàn)闆](méi)方法需要實(shí)現(xiàn)),任意對(duì)象都可以保存到空接口實(shí)例變量中。
空接口的定義方式:
1
2
type empty_int interface {
}
通常會(huì)簡(jiǎn)寫(xiě)為type empty_int interface{}。
更常見(jiàn)的,會(huì)直接使用interface{}作為一種類型,表示空接口。例如:
1
2
// 聲明一個(gè)空接口實(shí)例
var i interface{}
再比如函數(shù)使用空接口類型參數(shù):
func myfunc(i interface{})
在Go中很多地方都使用空接口類型的參數(shù),用的最多的fmt中的Print類方法:
1
2
$ go doc fmt Println
func Println(a 。..interface{}) (n int, err error)
空接口數(shù)據(jù)結(jié)構(gòu)
可以定義一個(gè)空接口類型的array、slice、map、struct等,這樣它們就可以用來(lái)存放任意類型的對(duì)象,因?yàn)槿我忸愋投紝?shí)現(xiàn)了空接口。
例如,創(chuàng)建一個(gè)空接口的slice:
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import “fmt”
func main() {
any := make([]interface{}, 5)
any[0] = 11
any[1] = “hello world”
any[2] = []int{11, 22, 33, 44}
for _, value := range any {
fmt.Println(value)
}
}
輸出結(jié)果:
1
2
3
4
5
11
hello world
[11 22 33 44]
《nil》
《nil》
顯然,通過(guò)空接口類型,Go也能像其它動(dòng)態(tài)語(yǔ)言一樣,在數(shù)據(jù)結(jié)構(gòu)中存儲(chǔ)任意類型的數(shù)據(jù)。
再比如,某個(gè)struct中,如果有一個(gè)字段想存儲(chǔ)任意類型的數(shù)據(jù),就可以將這個(gè)字段的類型設(shè)置為空接口:
1
2
3
4
type my_struct struct {
anything interface{}
anythings []interface{}
}
拷貝數(shù)據(jù)結(jié)構(gòu)到空接口數(shù)據(jù)結(jié)構(gòu)
前面解釋了任意類型的對(duì)象都能賦值給空接口實(shí)例。
1
2
3
var any interface{}
any = “hello world”
any = 11
空接口是一種接口,它是一種指針類型的數(shù)據(jù)類型,雖然不嚴(yán)謹(jǐn),但它確實(shí)保存了兩個(gè)指針,一個(gè)是對(duì)象的類型(或iTable),一個(gè)是對(duì)象的值。所以上面的賦值過(guò)程是讓空接口any保存各個(gè)數(shù)據(jù)對(duì)象的類型和對(duì)象的值。
換一種角度考慮,空接口有自己的內(nèi)存布局方式:兩個(gè)指針,占用兩個(gè)機(jī)器字長(zhǎng)。
Golang給的一個(gè)經(jīng)典的示例:將某個(gè)slice中的數(shù)據(jù)拷貝到空接口slice中將報(bào)錯(cuò)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import “fmt”
func main() {
testSlice := []int{11,22,33,44}
// 成功拷貝
var newSlice []int
newSlice = testSlice
fmt.Println(newSlice)
// 拷貝失敗
var any []interface{}
any = testSlice
fmt.Println(any)
}
這是因?yàn)槊總€(gè)空接口的內(nèi)存布局都占用兩個(gè)機(jī)器字長(zhǎng)的內(nèi)容。對(duì)于長(zhǎng)度為N的空接口slice來(lái)說(shuō),它的每個(gè)元素都是以2機(jī)器字長(zhǎng)為單元的連續(xù)空間,共占用N*2個(gè)機(jī)器字長(zhǎng)的空間。
而普通的slice,例如上面的testSlice,它的每個(gè)元素是int類型的,int類型的內(nèi)存布局和空接口不一樣。
這些對(duì)象的內(nèi)存布局在編譯期間就已經(jīng)確定好了,所以沒(méi)法直接將不同內(nèi)存布局的數(shù)據(jù)結(jié)構(gòu)進(jìn)行拷貝。
要想完成期待的拷貝,可以使用for-range的方式,將testSlice中的每個(gè)元素賦值給空接口slice的空接口元素:也就是一個(gè)個(gè)的空接口實(shí)例。
1
2
3
4
var any []interface{}
for _,value := range testSlice{
any = append(any,value)
}
這樣,空接口Slice中的每個(gè)空接口實(shí)例都指向更底層的各個(gè)數(shù)據(jù)對(duì)象。而不是像前面錯(cuò)誤的拷貝方式:每個(gè)空接口元素想要當(dāng)作這些數(shù)據(jù)對(duì)象。
不僅空接口的Slice如此,其它包含空接口的數(shù)據(jù)結(jié)構(gòu),也都類似。
審核編輯:黃飛
-
接口
+關(guān)注
關(guān)注
33文章
8691瀏覽量
151911 -
數(shù)據(jù)類型
+關(guān)注
關(guān)注
0文章
236瀏覽量
13662
原文標(biāo)題:空接口
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論