第46章:一些简单的总结

一些简单的总结

索引:

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

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

  • 字符串类型
  • 函数类型
  • 切片类型
  • 映射类型
  • 通道类型
  • 接口类型

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

哪些种类型的值可以用做内置len(以及capclosedeletemake)函数调用的实参?

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

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

各种容器类型比较

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

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

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

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

类型(TT{}是类型T的零值?
结构体类型
数组类型
切片类型
(零值用nil表示)
映射类型
(零值用nil表示)

各种类型的尺寸

详见值复制成本(第34章)一文。

哪些种类型的零值使用预声明的nil标识符表示?

下面这些类型的零值可以用预声明的nil标识符表示。

类型(TT(nil)的尺寸
指针1 word
切片3 words
映射1 word
通道1 word
函数1 word
接口2 words

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

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

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

详见方法(第22章)一文。

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

详见类型内嵌(第24章)一文。

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

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

函数返回类型其调用是否总是在编译时刻估值?
unsafe.Sizeofuintptr总是如此。

但是请注意,如果这样的一个函数调用的实参类型为一个类型参数,则此函数调用的结果将不被视为一个常量。
unsafe.Alignof
unsafe.Offsetof


len


int

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都为常量表达式的时候才在编译时刻估值。

哪些值是可寻址的?

请阅读此条问答(第51章)获取详情。

哪些类型不支持比较?

请阅读此条问答(第51章)获取详情。

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

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

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

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

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

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

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

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

  • 类型
  • 变量
  • 常量

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

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

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

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

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

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

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

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

  1. 向一个永不会被接收数据的通道发送数据。

    1. make(chan struct{}) <- struct{}{}
    2. // 或者
    3. make(chan<- struct{}) <- struct{}{}
  2. 从一个未被并且将来也不会被发送数据的(并且保证永不会被关闭的)通道读取数据。

    1. <-make(chan struct{})
    2. // 或者
    3. <-make(<-chan struct{})
    4. // 或者
    5. for range make(<-chan struct{}) {}
  3. 从一个nil通道读取或者发送数据。

    1. chan struct{}(nil) <- struct{}{}
    2. // 或者
    3. <-chan struct{}(nil)
    4. // 或者
    5. for range chan struct{}(nil) {}
  4. 使用一个不含任何分支的select流程控制代码块。

    1. select{}

几种衔接字符串的方法

详见字符串(第19章)一文。

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

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

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

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


本书由老貘历时三年写成。目前本书仍在不断改进和增容中。你的赞赏是本书和Go101.org网站不断增容和维护的动力。

(请搜索关注微信公众号“Go 101”或者访问github.com/golang101/golang101获取本书最新版)