开始之前
首先,这是一篇菜B写的文章,可能会有理解错误的地方,发现错误请斧正,谢谢。
为了治疗我的懒癌早期,我一次就不写得太多了,这个系列想写很久了,每次都是开了个头就没有再写。这次争取把写完,弄成一个系列。
此 nil 不等彼 nil
先声明,这个标题有标题党的嫌疑。
Go 的类型系统是比较奇葩的,nil 的含义跟其它语言有些差别,这里举个例子(可以直接进入 http://play.golang.org/p/ezFhXX0dnB 运行查看结果):
复制代码 代码如下:
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 的人来说比较费解,对我来说,这个算得上一门语言设计有歧义的地方(Golang FAQ 有对于此问题的描述,可以参考一下:http://golang.org/doc/faq#nil_error)。
简单的说就是 nil 代表 “zero value”(空值),对于不同类型,它具体所代表的值不同。比如上面的 a 为“*A 类型的空值”,而 ai 为“interface{} 类型的空值”。造成理解失误的最大问题在于,struct pointer 到 interface 有隐式转换(var ai interface{] = a,这里有个隐式转换),至于为什么对于 Go 这种在其它转换方面要求严格,而对于 interface 要除外呢,for convenience 吧,呵呵……
碰到了这个坑,我就开始好奇了,Go 的类型系统到底是什么样的?
Go 内存模型 - interface
概述
为了读懂下面的内容,你需要:
了解 C、Go 语言
Go 1.3 源代码 (https://go.googlecode.com/archive/go1.3.zip)
PS: 由于 Go 用到了 Plan9 C 这个小众的C编译器的扩展,比如在函数签名中使用 · 字符以区分 package/function(比如runtime·panic),这对理解不会产生什么影响。
PSS: 对于 Go runtime,可以参考src/pkg/reflect(reflect包)中的的代码,对类型系统的实现的理解有帮助。
Go 语言的类型定义可以在 src/pkg/runtime/ 目录下找到,主要由以下几个文件构成:
1.runtime.h
2.type.h
对于 interface 类型,主要看下面几个结构体定义:
1.InterfaceType
2.Itab
3.Iface
4.Eface
它们的C语言定义如下 (可以在 runtime.h 中找到):
InterfaceType:
代表了总的 interface 类型,其中:
1.Type: 类型描述,所有的类型都有这个类型描述(比如 array, map, slice)
2.mhdr 以及 m: interface 接口方法列表
复制代码 代码如下:
struct InterfaceType
{
Type;
Slice mhdr;
IMethod m[];
};
Itab:
类似于虚函数表,该表不会被GC回收,其中:
1.inter: 指向具体的 interface 类型
2.type: 具体实现类型, 也即 receiver type
3.link: 指向下一个函数表,因为 interface 可以 embed 多个 interface,因此实现为一个链表形式
4.bad: <略>
5.unsued: <略>
6.fun: 函数列表,每个元素是一个指向具体函数实现的指针
复制代码 代码如下:
struct Itab
{
InterfaceType* inter;
Type* type;
Itab* link;
int32 bad;
int32 unused;
void (*fun[])(void);
};
Iface:
该类型为一般的 interface 类型所对应的数据结构,其中:
1.tab: 参见 Itab 的说明,尤其是 Itab::link
2.data: 指向具体数据(比如指向struct,当然,如果一个数据不超过一个字长,那么这个data就可以直接存放,不需要指针再做以及跳转)
复制代码 代码如下:
struct Iface
{
Itab* tab;
void* data;
};
Eface:
该类型为 interface{} (empty interface) 所对应的数据结构,其中:
1.type: 具体实现类型, 也即 receiver type
2.data: 同 Iface
复制代码 代码如下:
struct Eface
{
Type* type;
void* data;
};
他们的依赖关系如下图所示:
先到这里,下一篇将会举例子说明给一个 interface{} 类型的变量赋值后,其具体的内存结构是怎么样的。
打了几个小时,真费时间,争取这个系列不坑 (逃
Golang,内存模型
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]