開始之前
首先,這是一篇菜B寫的文章,可能會(huì)有理解錯(cuò)誤的地方,發(fā)現(xiàn)錯(cuò)誤請斧正,謝謝。
為了治療我的懶癌早期,我一次就不寫得太多了,這個(gè)系列想寫很久了,每次都是開了個(gè)頭就沒有再寫。這次爭取把寫完,弄成一個(gè)系列。
此 nil 不等彼 nil
先聲明,這個(gè)標(biāo)題有標(biāo)題黨的嫌疑。
Go 的類型系統(tǒng)是比較奇葩的,nil 的含義跟其它語言有些差別,這里舉個(gè)例子(可以直接進(jìn)入 http://play.golang.org/p/ezFhXX0dnB 運(yùn)行查看結(jié)果):
復(fù)制代碼 代碼如下:
package main
import "fmt"
type A struct {
}
func main() {
var a *A = nil
var ai interface{} = a
var ei interface{} = nil
fmt.Printf("ai == nil: %v\n", ai == nil)
fmt.Printf("ai == ei: %v\n", ai == ei)
fmt.Printf("ei == a: %v\n", a == ei)
fmt.Printf("ei == nil: %v\n", ei == nil)
}
// -> 輸出
// ai == nil: false
// ai == ei: false
// ei == a: false
// ei == nil: true
這里 ai != nil,對于沒有用過 Go 的人來說比較費(fèi)解,對我來說,這個(gè)算得上一門語言設(shè)計(jì)有歧義的地方(Golang FAQ 有對于此問題的描述,可以參考一下:http://golang.org/doc/faq#nil_error)。
簡單的說就是 nil 代表 “zero value”(空值),對于不同類型,它具體所代表的值不同。比如上面的 a 為“*A 類型的空值”,而 ai 為“interface{} 類型的空值”。造成理解失誤的最大問題在于,struct pointer 到 interface 有隱式轉(zhuǎn)換(var ai interface{] = a,這里有個(gè)隱式轉(zhuǎn)換),至于為什么對于 Go 這種在其它轉(zhuǎn)換方面要求嚴(yán)格,而對于 interface 要除外呢,for convenience 吧,呵呵……
碰到了這個(gè)坑,我就開始好奇了,Go 的類型系統(tǒng)到底是什么樣的?
Go 內(nèi)存模型 - interface
概述
為了讀懂下面的內(nèi)容,你需要:
了解 C、Go 語言
Go 1.3 源代碼 (https://go.googlecode.com/archive/go1.3.zip)
PS: 由于 Go 用到了 Plan9 C 這個(gè)小眾的C編譯器的擴(kuò)展,比如在函數(shù)簽名中使用 · 字符以區(qū)分 package/function(比如runtime·panic),這對理解不會(huì)產(chǎn)生什么影響。
PSS: 對于 Go runtime,可以參考src/pkg/reflect(reflect包)中的的代碼,對類型系統(tǒng)的實(shí)現(xiàn)的理解有幫助。
Go 語言的類型定義可以在 src/pkg/runtime/ 目錄下找到,主要由以下幾個(gè)文件構(gòu)成:
1.runtime.h
2.type.h
對于 interface 類型,主要看下面幾個(gè)結(jié)構(gòu)體定義:
1.InterfaceType
2.Itab
3.Iface
4.Eface
它們的C語言定義如下 (可以在 runtime.h 中找到):
InterfaceType:
代表了總的 interface 類型,其中:
1.Type: 類型描述,所有的類型都有這個(gè)類型描述(比如 array, map, slice)
2.mhdr 以及 m: interface 接口方法列表
復(fù)制代碼 代碼如下:
struct InterfaceType
{
Type;
Slice mhdr;
IMethod m[];
};
Itab:
類似于虛函數(shù)表,該表不會(huì)被GC回收,其中:
1.inter: 指向具體的 interface 類型
2.type: 具體實(shí)現(xiàn)類型, 也即 receiver type
3.link: 指向下一個(gè)函數(shù)表,因?yàn)?interface 可以 embed 多個(gè) interface,因此實(shí)現(xiàn)為一個(gè)鏈表形式
4.bad: 略>
5.unsued: 略>
6.fun: 函數(shù)列表,每個(gè)元素是一個(gè)指向具體函數(shù)實(shí)現(xiàn)的指針
復(fù)制代碼 代碼如下:
struct Itab
{
InterfaceType* inter;
Type* type;
Itab* link;
int32 bad;
int32 unused;
void (*fun[])(void);
};
Iface:
該類型為一般的 interface 類型所對應(yīng)的數(shù)據(jù)結(jié)構(gòu),其中:
1.tab: 參見 Itab 的說明,尤其是 Itab::link
2.data: 指向具體數(shù)據(jù)(比如指向struct,當(dāng)然,如果一個(gè)數(shù)據(jù)不超過一個(gè)字長,那么這個(gè)data就可以直接存放,不需要指針再做以及跳轉(zhuǎn))
復(fù)制代碼 代碼如下:
struct Iface
{
Itab* tab;
void* data;
};
Eface:
該類型為 interface{} (empty interface) 所對應(yīng)的數(shù)據(jù)結(jié)構(gòu),其中:
1.type: 具體實(shí)現(xiàn)類型, 也即 receiver type
2.data: 同 Iface
復(fù)制代碼 代碼如下:
struct Eface
{
Type* type;
void* data;
};
他們的依賴關(guān)系如下圖所示:
先到這里,下一篇將會(huì)舉例子說明給一個(gè) interface{} 類型的變量賦值后,其具體的內(nèi)存結(jié)構(gòu)是怎么樣的。
打了幾個(gè)小時(shí),真費(fèi)時(shí)間,爭取這個(gè)系列不坑 (逃
您可能感興趣的文章:- django數(shù)據(jù)關(guān)系一對多、多對多模型、自關(guān)聯(lián)的建立
- django的ORM模型的實(shí)現(xiàn)原理
- 解決golang內(nèi)存溢出的方法
- 解決MongoDB 排序超過內(nèi)存限制的問題
- 詳解Go內(nèi)存模型