Go基礎系列:空接口

空接口

空接口是指沒有定義任何接口方法的接口。沒有定義任何接口方法,意味着Go中的任意對象均可以實現空接口(由於沒方法須要實現),任意對象均可以保存到空接口實例變量中數據結構

空接口的定義方式:app

type empty_int interface {
}

一般會簡寫爲type empty_int interface{}函數

更常見的,會直接使用interface{}做爲一種類型,表示空接口。例如:佈局

// 聲明一個空接口實例
var i interface{}

再好比函數使用空接口類型參數:指針

func myfunc(i interface{})

在Go中不少地方都使用空接口類型的參數,用的最多的fmt中的Print類方法:code

$ go doc fmt Println
func Println(a ...interface{}) (n int, err error)

空接口數據結構

能夠定義一個空接口類型的array、slice、map、struct等,這樣它們就能夠用來存聽任意類型的對象,由於任意類型都實現了空接口。對象

例如,建立一個空接口的slice:接口

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)
    }
}

輸出結果:內存

11
hello world
[11 22 33 44]
<nil>
<nil>

顯然,經過空接口類型,Go也能像其它動態語言同樣,在數據結構中存儲任意類型的數據。編譯

再好比,某個struct中,若是有一個字段想存儲任意類型的數據,就能夠將這個字段的類型設置爲空接口:

type my_struct struct {
    anything interface{}
    anythings []interface{}
}

拷貝數據結構到空接口數據結構

前面解釋了任意類型的對象都能賦值給空接口實例。

var any interface{}
any = "hello world"
any = 11

空接口是一種接口,它是一種指針類型的數據類型,雖然不嚴謹,但它確實保存了兩個指針,一個是對象的類型(或iTable),一個是對象的值。因此上面的賦值過程是讓空接口any保存各個數據對象的類型和對象的值。

換一種角度考慮,空接口有本身的內存佈局方式:兩個指針,佔用兩個機器字長。

Golang給的一個經典的示例:將某個slice中的數據拷貝到空接口slice中將報錯。

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)
}

這是由於每一個空接口的內存佈局都佔用兩個機器字長的內容。對於長度爲N的空接口slice來講,它的每一個元素都是以2機器字長爲單元的連續空間,共佔用N*2個機器字長的空間。

而普通的slice,例如上面的testSlice,它的每一個元素是int類型的,int類型的內存佈局和空接口不同。

這些對象的內存佈局在編譯期間就已經肯定好了,因此無法直接將不一樣內存佈局的數據結構進行拷貝。

要想完成期待的拷貝,可使用for-range的方式,將testSlice中的每一個元素賦值給空接口slice的空接口元素:也就是一個個的空接口實例。

var any []interface{}
for _,value := range testSlice{
    any = append(any,value)
}

這樣,空接口Slice中的每一個空接口實例都指向更底層的各個數據對象。而不是像前面錯誤的拷貝方式:每一個空接口元素想要看成這些數據對象。

不只空接口的Slice如此,其它包含空接口的數據結構,也都相似。

相關文章
相關標籤/搜索