• 一些简单的总结
    • 哪些种类型的值可以有间接底层部分?
    • 哪些种类型的值可以用做内置len(以及cap、close、delete和make)函数调用的实参?
    • 各种容器类型比较
    • 哪些种类型的值可以用组合字面值(T{…})表示?
    • 我们可以为什么样的类型声明方法?
    • 什么样的类型可以被内嵌在结构体类型中?
    • 哪些函数调用将在编译时刻被估值?
    • 哪些值是可寻址的?
    • 哪些类型不支持比较?
    • 哪些代码元素允许被声明却不使用?
    • 哪些有名代码元素可多个被一起声明在一对小括号()中?
    • 哪些代码元素的声明可以被声明在函数内也可以被声明在函数外?
    • 哪些表达式的估值结果可以包含一个额外的可选的值?
    • 几种导致当前协程永久阻塞的方法
    • 几种衔接字符串的方法
    • 官方标准编译器中实现的一些优化
    • 在Go程序运行中将会产生恐慌或者崩溃的情形

    一些简单的总结

    哪些种类型的值可以有间接底层部分?

    在Go中,下列种类的类型的值可以有间接底层部分:

    • 字符串类型
    • 函数类型
    • 切片类型
    • 映射类型
    • 通道类型
    • 接口类型 注意:此答案基于标准编译器的实现。事实上,函数类型的值是否有间接底层部分是难以证明的。另外,字符串和接口类型的值在逻辑上应该被认为是不含间接底层部分。请阅读值部一文获取更多信息。

    哪些种类型的值可以用做内置len(以及cap、close、delete和make)函数调用的实参?

    lencapclosedeletemake
    字符串值可以
    数组或者数组指针值可以可以
    切片值可以可以可以
    映射值可以可以可以
    通道值可以可以可以可以

    可以被用做内置函数len调用的参数的值的类型都可以被称为(广义上的)容器类型。这些容器类型的值都可以跟在for-range循环的range关键字后。

    各种容器类型比较

    类型容器值是否支持添加新的元素?容器值中的元素是否可以被替换?容器值中的元素是否可寻址?访问容器值元素是否会更改容器长度?容器值是否可以有间接底层部分?
    字符串是(1)
    数组是(2)是(2)
    切片否(3)
    映射
    通道是(4)

    (1) 对于标准编译器和运行时来说。(2) 对于可寻址的数组值来说。(3) 一般说来,一个切片的长度只能通过将另外一个切片赋值给它来被整体替换修改,这里我们不视这种情况为“添加新的元素”。其实,切片的长度也可以通过调用reflect.SetLen来单独修改。增加切片的长度可以看作是一种变相的向切片添加元素。但reflect.SetLen函数的效率很低,因此很少使用。(4) 对于带缓冲并且缓冲未满的通道来说。

    哪些种类型的值可以用组合字面值(T{…})表示?

    下面在四种类型的值(除了切片和映射类型的零值)可以用组合字面值表示。

    类型(TT{}是类型T的零值?
    结构体类型
    数组类型
    切片类型否(零值用nil表示)
    映射类型否(零值用nil表示)
    ### 各种类型的尺寸 详见值复制成本一文。 ### 哪些种类型的零值使用预声明的nil标识符表示? 下面这些类型的零值可以用预声明的nil标识符表示。
    类型(TT(nil)的尺寸
    指针1 word
    切片3 words
    映射1 word
    通道1 word
    函数1 word
    接口2 words

    上表列出的尺寸为标准编译器的结果。一个word(原生字)在32位的架构中为4个字节,在64位的架构中为8个字节。一个Go值的间接底层部分未统计在尺寸中。

    一个类型的零值的尺寸和其它非零值的尺寸是一致的。

    我们可以为什么样的类型声明方法?

    详见方法一文。

    什么样的类型可以被内嵌在结构体类型中?

    详见类型内嵌一文。

    哪些函数调用将在编译时刻被估值?

    如果一个函数调用在编译时刻被估值,则估值结果为一个常量。

    函数返回类型其调用是否总是在编译时刻估值?
    unsafe.Sizeofuintptr
    unsafe.Alignof
    unsafe.Offsetof
    lenint否 Go语言白皮书中提到:

    • 如果表达式s表示一个字符串常量,则表达式len(s)将在编译时刻估值;
    • 如果表达式s表示一个数组或者数组的指针,并且s中不含有数据接收操作和估值结果为非常量的函数调用,则表达式len(s)cap(s)将在编译时刻估值。
    cap
    real默认类型为float64(结果为类型不确定值)否 Go语言白皮书提到:表达式real(s)imag(s)s为一个复数常量表达式时才在编译时刻估值。
    imag
    complex默认类型为complex128(结果为类型不确定值)否 Go语言白皮书提到:表达式complex(sr, si)只有在srsi都为常量表达式的时候才在编译时刻估值。

    哪些值是可寻址的?

    请阅读此条问答获取详情。

    哪些类型不支持比较?

    请阅读此条问答获取详情。

    哪些代码元素允许被声明却不使用?

    允许被声明却不使用?
    包引入不允许
    类型允许
    变量包级全局变量允许,但局部变量不允许(对于官方标准编译器)。
    常量允许
    函数允许
    跳转标签不允许

    哪些有名代码元素可多个被一起声明在一对小括号()中?

    下面这些同种类的代码元素可多个被一起声明在一对小括号()中:

    • 包引入
    • 类型
    • 变量
    • 常量

    函数是不能多个被一起声明在一对小括号()中的。跳转标签也不能。

    哪些代码元素的声明可以被声明在函数内也可以被声明在函数外?

    下面这些代码元素的声明既可以被声明在函数内也可以被声明在函数外:

    • 类型
    • 变量
    • 常量

    包引入必须被声明在其它种类的代码元素的声明之前。

    函数必须声明在任何函数体之外。匿名函数可以定义在函数体内,但那不属于声明。

    跳转标签必须声明在函数体内。

    哪些表达式的估值结果可以包含一个额外的可选的值?

    下列表达式的估值结果可以包含一个额外的可选的值:

    语法额外的可选的值(语法示例中的ok)的含义舍弃额外的可选的值会对估值行为发生影响吗?
    映射元素访问e, ok = aMap[key]键值key对应的条目是否存储在映射值中
    数据接收e, ok = <- aChannel被接收到的值e是否是在通道关闭之前发送的
    类型断言v, ok = anInterface.(T)接口值的动态类型是否为类型T是(当可选的值被舍弃并且断言失败的的时候,将产生一个恐慌。)

    几种导致当前协程永久阻塞的方法

    无需引入任何包,我们可以使用下面几种方法使当前协程永久阻塞:

    • 向一个永不会被接收数据的通道发送数据。
    1. make(chan struct{}) <- struct{}{}
    2. // 或者
    3. make(chan<- struct{}) <- struct{}{}
    • 从一个未被并且将来也不会被发送数据的(并且保证永不会被关闭的)通道读取数据。
    1. <-make(chan struct{})
    2. // 或者
    3. <-make(<-chan struct{})
    4. // 或者
    5. for range make(<-chan struct{}) {}
    • 从一个nil通道读取或者发送数据。
    1. chan struct{}(nil) <- struct{}{}
    2. // 或者
    3. <-chan struct{}(nil)
    4. // 或者
    5. for range chan struct{}(nil) {}
    • 使用一个不含任何分支的select流程控制代码块。
    1. select{}

    几种衔接字符串的方法

    详见字符串一文。

    官方标准编译器中实现的一些优化

    详见Go语言101维基中的一文。

    在Go程序运行中将会产生恐慌或者崩溃的情形

    详见Go语言101维基中的一文。

    Go语言101项目目前同时托管在Github和Gitlab上。欢迎各位在这两个项目中通过提交bug和PR的方式来改进完善Go语言101中的各篇文章。

    本书微信公众号名称为"Go 101"。每个工作日此公众号将尽量发表一篇和Go语言相关的原创短文。各位如果感兴趣,可以搜索关注一下。

    赞赏