《Go语言精进之路》10-12章笔记
本文最后更新于 390 天前,其中的信息可能已经有所发展或是发生改变。

第10条 使用iota实现枚举常量

Go的const语法提供了“隐式重复前一个非空表达式”的机制,来看下面的代码:

image-20220723150820147

常量定义的后两行没有显式给予初始赋值,Go编译器将为其隐式使用第一行的表达式,这样上述定义等价于:
image-20220723150836255


iota是Go语言的一个预定义标识符,它表示的是const声明块(包括单行声明)中每个常量所处位置在块中的偏移值(从零开始)。

iota的值和在const块中第几行有关,并不是在哪第一次使用都是0


位于同一行的iota即便出现多次,其值也是一样的:

image-20220723150910193


如果要略过iota = 0,而从iota = 1开始正式定义枚举常量,可以效仿下面的代码:

image-20220723150924151


image-20220723151020533

iota虽然是第一次使用,但它在const块的第二行,所以值为1,而不是0


举一个“反例”:在一些枚举常量名称与其初始值有强烈对应关系的时候,枚举常量会直接使用显式数值作为常量的初始值。这样的情况极其少见,我在Go标准库中仅找到这一处:

image-20220723151057900

一般使用iota


第11条 尽量定义零值可用的类型

11.2 零值可用

Go从诞生以来就一直秉承着尽量保持“零值可用”的理念


切片零值可用

image-20220730094923967


string方法零值可用

image-20220730095049626

image-20220730095107740


锁零值可用

image-20220730095243034


bytes.Buffer零值可用

image-20220730095327838

这是因为bytes.Buffer结构体用于存储数据的字段buf支持零值可用策略的切片类型

image-20220730095426099


Go语言零值可用的理念给内置类型、标准库的使用者带来很多便利。不过Go并非所有类型都是零值可用的,并且零值可用也有一定的限制,比如:在append场景下,零值可用的切片类型不能通过下标形式操作数据:

image-20220730095454692


另外,像map这样的原生类型也没有提供对零值可用的支持

image-20220730095512865


零值可用的类型要注意尽量避免值复制:

image-20220730095547771

我们可以通过指针方式传递类似Mutex这样的类型:
image-20220730095601806

这点不理解,这个零值就是个nil,为啥不能赋值给其他变量呢?

一番测试后,搞明白了

type Person struct {
    age     int
    address string
}

func main() {
    var p Person
    fmt.Printf("p:%v\n", p)         // p:{0 }
    fmt.Printf("p:%p\n", &p)        // p:0xc0000ac018
    fmt.Printf("p.age:%v\n", p.age) // p.age:0

    var p1 *Person
    fmt.Printf("p1:%v\n", p1)         // p1:<nil>
    fmt.Printf("p1:%p\n", &p1)        // p1:0xc0000b4020
    fmt.Printf("p1.age:%v\n", p1.age) // 报错
}
  • 未赋值的结构体变量是分配了内存的,不等于nil,并且结构体内的字段都赋予了初始值。

  • 未赋值的指针等于nil,未分配内存。

  • 这就能解释为什么mutex未赋值就能调用自己的Lock方法而不会NPE。

    var lock sync.Mutex
    lock.Lock()

保持与Go一致的理念,给自定义的类型一个合理的零值,并尽量保持自定义类型的零值可用,这样我们的Go代码会更加符合Go语言的惯用法。


第12条 使用复合字面值作为初值构造器

image-20220730104041212


12.1 结构体复合字面值

一旦该结构体类型增加了一个新的字段,即使是未导出的,这种值构造方式也将导致编译失败,也就是说,应该将

image-20220730104547885

替换为

image-20220730104608842

显然,Go推荐使用field:value的复合字面值形式对struct类型变量进行值构造,这种值构造方式可以降低结构体类型使用者与结构体类型设计者之间的耦合。

可读性更好、增加字段不会编译错误(解耦)、无顺序要求、不容易出错


复合字面值作为结构体值构造器的大量使用,使得即便采用类型零值时我们也会使用字面值构造器形式:
s := myStruct{} // 常用
而较少使用new这一个Go预定义的函数来创建结构体变量实例:
s := new(myStruct) // 较少使用


12.3 map复合字面值

对于数组/切片类型而言,当元素为复合类型时,可以省去元素复合字面量中的类型,比如:

image-20220730105926373

还有map


对于key或value为指针类型的情况,也可以省略“&T”


对于零值不适用的场景,我们要为变量赋予一定的初值。对于复合类型,我们应该首选Go提供的复合字面值作为初值构造器。对于不同复合类型,我们要记住下面几点:

对于零值不适用的场景,我们要为变量赋予一定的初值。对于复合类型,我们应该首选Go提供的复合字面值作为初值构造器。对于不同复合类型,我们要记住下面几点:

1、使用field:value形式的复合字面值为结构体类型的变量赋初值;
2、在为稀疏元素赋值或让编译器推导数组大小的时候,多使用index:value的形式为数组/切片类型变量赋初值;
3、使用key:value形式的复合字面值为map类型的变量赋初值。(Go1.5版本后,复合字面值中的key和value类型均可以省略不写。)


作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇