《GO in action》第5章(Go语言的类型系统)读书笔记

5.1 用户定义的类型

不使用字段名创建结构类型的值,这咱形式下值的顺序很重要。

type user struct {
    name  string
    age   int
    email string
}

lisa := user{"Lisa", 20, "lisa@email.com"}

两种不同类型的值即便相互兼容,也不能互相赋值。编译器不会对不同类型的值做隐式转换。

type Duration int64

func main() {
    var dur Duration
    dur = int64(100)
}

上述代码会产生编译错误,int64的值不能做为类型Duration的值来用。

5.2 方法

如果一个函数的接收者,这个函数就被称为方法。

Go语言里有两种类型的接收者: 值接收者和指针接收者。

值接收者使用值的副本来调用方法,指针接收者使用实际值来调用方法。

5.3 类型的本质

5.3.1 内置类型

内置类型是由语言提供的一组类型。分别是数值类型,字符类型和布尔类型。这些类型本质上是原始的类型。因此,当对这些值进行增加或者删除的时候,会创建一个新值。

5.3.2 引用类型

Go语言里的引用类型有如下几个:切片、映射、通道、接口和函数类型。当上声明述类型的变量时,创建的变量被称作标头值。每个引用类型创建的标头值是包含一个指向底层数据结构的指针。每个引用类型还包含一组独特的字段,用于管理底层数据结构。因为标头值是为复制而设计的,所以永远不需要共享一个引用类型的值。标头值里包含一个指针,因此通过复制来传递一个引用类型的值的副本,本质上就是在共享底层数据结构。

5.3.3 结构类型

是使用值接收者还是指针接收者,不应该由该方法是否修改了接收到的值来决定。这个决策应该基于类型的本质。(原始类型,使用值接收者。非原始类型使用指针接收者。)这条规则的一个例外是,需要让类型值符合某个掊的时候,即便类型的本质是非原始的,也可以选择使用值接收者声明方法。

5.4 接口

5.4.2 实现

接口是用来定义行为的类型。这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。

用户定义的类型可以实现任何接口,所以对接口值方法的调用自然就是一种多态。在这个关系里,用户定义的类型通常叫作实体类型。

接口值是一个两个字长度的数据结构,第一个字包含一个指向内部表的指针。这个内部表叫作iTable,包含了所存储的值的类型值信息。iTable包含了已存储的值的类型信息以及与这个值相关联的一组方法。第二个字是一个指向所存储值的指针。将类型信息和指针组合在一起,就将这两个值组成了一种特殊的关系。

type notifier interface {
    notify()
}

type user struct {
    name  string
    email string
}

// notify implements a method with a pointer receiver.
func (u *user) notify() {
    fmt.Printf("Sending user email to %s<%s>\n",
        u.name,
        u.email)
}

下图展示了在user类型赋值后接口变量的值的内部布局


image

下图展示了一个指针赋值给接口之后发生的变化。


image

5.4.3 方法集

方法集定义了接口的接受规则。

方法集定义了一组关联到给定类型的值或者指针的方法。定义方法时使用的接收者的类型决定了这个方法是关联到值,还是关联到指针,还是两个都关联。

从接收者类型的角度来看方法集

Methods Rceivers Values
(t T) T and *T
(t *T) *T

上面的规则是说,如果使用指针接收者来实现一个接口,那么只有指向那个类型的指针才能够实现对应的接口。如果使用值接收者来实现一个接口,那么那个类型的值和指针都能够实现对应的接口。之所以有这种限制是因为编译器并不是总能自动获得一个值的地址。

// main is the entry point for the application.
func main() {
    // Create a value of type User and send a notification.
    u := user{"Bill", "bill@email.com"}

    sendNotification(u)

    // ./listing36.go:32: cannot use u (type user) as type
    //                     notifier in argument to sendNotification:
    //   user does not implement notifier
    //                          (notify method has pointer receiver)
}

func sendNotification(n notifier) {
    n.notify()
}

将上述代码做如下改动,不再报错:

func main() {
    u := user{"Bill", "bill@email.com"}
    sendNotification(&u)
}

再看下面的例子

image
  • 23,27行都会输出demoName
  • 30行正确
  • 31行报错。因为setName方法的接收者是指针类型,所以编译器认为p2并没有实现setName方法。

5.5 嵌入类型

可以直接通过外部类型的值来访问内部类型的标识符。

内部类型实现的接口会自动提升到外部类型。

如果外部类型实现与内部类型同样的方法,则内部类型的实现就不会被提升。不过内部类型的值会一直存在,可以通过直接访问内部类型的值,来调用没有被提升的内部类型实现的方法。

type user struct {
    name  string
    email string
}

func (u *user) notify() {
    fmt.Printf("Send user email to %s<%s>\n", u.name, u.email)
}

type admin struct {
    user
    level string
}

func (a *admin) notify() {
    fmt.Printf("Send admin email to %s<%s>\n", a.name, a.email)
}

func main() {
    ad := admin{
        user: user{
            name:  "ball",
            email: "ball@email.com",
        },
        level: "super",
    }

    //内部类型的方法没有被提升
    ad.notify()
    //调用内部类型的方法
    ad.user.notify()
}

5.6 公开或未公开的标识符

好的实践是使用与代码所在文件夹一样的名字作为包名。

当一个标识符的名字以小写字母开头时,这个标识符就是未公开的,即包外的代码不可见。

将工厂函数命名为New是Go语言的一个习惯。

即便内部类型是未公开的,内部类型里声明的字段依旧可以是公开的。当内部类型提升到了外部类型,这些公开的字段就可以通过外部类型的字段值来访问。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容