各种类型复制的时候的花费
本节标题也可以叫做“各种类型的值的大小” (the sizes of values of all kinds of types),底层可被不同的值共享的数据的大小未被计算。
下面的表格中一个 word
在32bit操作系统中代表4个字节,在64bit操作系统中代表8个字节,内容基于官方的Go 1.7的编译器。
Type Cost Of Value Copying (Value Size) bool 1 byte int8, uint8, byte 1 byte int16, uint16 2 bytes int32, uint32, rune 4 bytes int64, uint64 8 bytes int, uint, uintptr 1 word string 2 words pointer 1 word slice 3 words map 1 word channel 1 word function 1 word interface 2 words struct the sum of sizes of all fields array (element value size) * (array length)
本节标题也可以叫做“各种类型的值的大小” (the sizes of values of all kinds of types),底层可被不同的值共享的数据的大小未被计算。
下面的表格中一个 word
在32bit操作系统中代表4个字节,在64bit操作系统中代表8个字节,内容基于官方的Go 1.7的编译器。
Type | Cost Of Value Copying (Value Size) |
---|---|
bool | 1 byte |
int8, uint8, byte | 1 byte |
int16, uint16 | 2 bytes |
int32, uint32, rune | 4 bytes |
int64, uint64 | 8 bytes |
int, uint, uintptr | 1 word |
string | 2 words |
pointer | 1 word |
slice | 3 words |
map | 1 word |
channel | 1 word |
function | 1 word |
interface | 2 words |
struct | the sum of sizes of all fields |
array | (element value size) * (array length) |
可使用内建函数的类型 (len
、cap
、close
、delete
、make
)
len cap close delete make string Yes array (and array pointer) Yes Yes slice Yes Yes Yes map Yes Yes Yes channel Yes Yes Yes Yes
上面的所有类型都可以使用 range
遍历。
可以用作len
函数参数的类型也叫做容器类型。
len | cap | close | delete | make | |
---|---|---|---|---|---|
string | Yes | ||||
array (and array pointer) | Yes | Yes | |||
slice | Yes | Yes | Yes | ||
map | Yes | Yes | Yes | ||
channel | Yes | Yes | Yes | Yes |
上面的所有类型都可以使用 range
遍历。
可以用作len
函数参数的类型也叫做容器类型。
内建容器类型的值比较
假定容器的值可寻址(addressable)。
Type 长度可变 元素可更新 元素可寻址 查找会更改容器的长度 底层元素可以共享 string No No No No Yes array No Yes Yes No No slice No Yes Yes No Yes map Yes Yes No No Yes channel Yes No No Yes Yes
假定容器的值可寻址(addressable)。
Type | 长度可变 | 元素可更新 | 元素可寻址 | 查找会更改容器的长度 | 底层元素可以共享 |
---|---|---|---|---|---|
string | No | No | No | No | Yes |
array | No | Yes | Yes | No | No |
slice | No | Yes | Yes | No | Yes |
map | Yes | Yes | No | No | Yes |
channel | Yes | No | No | Yes | Yes |
组合类型T{...}
的值比较
Type (T
) T{}
是类型T
的零值?struct Yes array Yes slice No (零值是 nil
) map No (零值是 nil
)
Type (T ) | T{} 是类型T 的零值? |
---|---|
struct | Yes |
array | Yes |
slice | No (零值是 nil ) |
map | No (零值是 nil ) |
零值是nil
的类型
Type (T) Size Of T(nil) pointer 1 word slice 3 words map 1 word channel 1 word function 1 word interface 2 words
这些类型的零值的大小和上面类型的大小保持一致。
Type (T) | Size Of T(nil) |
---|---|
pointer | 1 word |
slice | 3 words |
map | 1 word |
channel | 1 word |
function | 1 word |
interface | 2 words |
这些类型的零值的大小和上面类型的大小保持一致。
编译时被执行的函数
如果函数在编译时被执行,那么它的返回值是常量。
如果函数在编译时被执行,那么它的返回值是常量。
不能被寻址的值
下面的值不能被寻址(addresses):
- bytes in strings:字符串中的字节
- map elements:map中的元素
- dynamic values of interface values (exposed by type assertions):接口的动态值
- constant values:常量
- literal values:字面值
- package level functions:包级别的函数
- methods (used as function values):方法
- intermediate values:中间值
- function callings
- explicit value conversions
- all sorts of operations, except pointer dereference operations, but including:
- channel receive operations
- sub-string operations
- sub-slice operations
- addition, subtraction, multiplication, and division, etc.
注意, &T{}
相当于tmp := T{}; (&tmp)
的语法糖,所以&T{}
可合法不意味着T{}
可寻址。
下面的值可以寻址:
- variables
- fields of addressable structs
- elements of addressable arrays
- elements of any slices (whether the slices are addressable or not)
- pointer dereference operations
下面的值不能被寻址(addresses):
- bytes in strings:字符串中的字节
- map elements:map中的元素
- dynamic values of interface values (exposed by type assertions):接口的动态值
- constant values:常量
- literal values:字面值
- package level functions:包级别的函数
- methods (used as function values):方法
- intermediate values:中间值
- function callings
- explicit value conversions
- all sorts of operations, except pointer dereference operations, but including:
- channel receive operations
- sub-string operations
- sub-slice operations
- addition, subtraction, multiplication, and division, etc.
注意, &T{}
相当于tmp := T{}; (&tmp)
的语法糖,所以&T{}
可合法不意味着T{}
可寻址。
下面的值可以寻址:
- variables
- fields of addressable structs
- elements of addressable arrays
- elements of any slices (whether the slices are addressable or not)
- pointer dereference operations
不支持比较的类型
下面的类型不支持直接比较:
- map
- slice
- function
- struct types containing incomparable fields
- array types with incomparable elements
这些不能直接比较的类型不能用做map的key值。
注意:尽管map、slice、function类型不支持直接比较,但是它们的值却可以和nil
直接比较。如果两个接口的动态类型不能比较,运行时比较这两个接口会panic,除非其中一个的动态值是untyped nil。
下面的类型不支持直接比较:
- map
- slice
- function
- struct types containing incomparable fields
- array types with incomparable elements
这些不能直接比较的类型不能用做map的key值。
注意:尽管map、slice、function类型不支持直接比较,但是它们的值却可以和nil
直接比较。如果两个接口的动态类型不能比较,运行时比较这两个接口会panic,除非其中一个的动态值是untyped nil。
可命名的源代码元素
下面的源代码元素可以命名,名称必须是 Identifier
可以使用 _
做名称? package No import Yes type Yes variable Yes constant Yes function Yes label Yes
下面的源代码元素可以命名,名称必须是 Identifier
可以使用 _ 做名称? | |
---|---|
package | No |
import | Yes |
type | Yes |
variable | Yes |
constant | Yes |
function | Yes |
label | Yes |
命名的源代码元素可以使用 ()
分组声明
下面的类型可以使用()
分组生命
- import
- type
- variable
- constant
函数和标签(label)不能使用()
分组声明。
下面的类型可以使用()
分组生命
- import
- type
- variable
- constant
函数和标签(label)不能使用()
分组声明。
可以在函数内外声明的源代码元素
下面的类型可以声明在函数内,也可以声明在函数外:
- type
- variable
- constant
import
必须在其它元素的声明的前面(package
语句的后面)。
函数在其它函数的外面声明。(译者注:函数变量/匿名函数可以在函数内声明)
标签(label)必须声明在函数内。
下面的类型可以声明在函数内,也可以声明在函数外:
- type
- variable
- constant
import
必须在其它元素的声明的前面(package
语句的后面)。
函数在其它函数的外面声明。(译者注:函数变量/匿名函数可以在函数内声明)
标签(label)必须声明在函数内。
可以返回一个可选bool返回值的表达式
下面的表达式可以返回一个可选的bool值:
可选的bool返回值的意义 忽略可选值会影响程序的行为? map element access map中是否包含要 No channel value receive 在channel关闭前收到的值是否已发出 No type assertion 接口的动态类型是否符合asserted type Yes
(当可选值被忽略时,如果类型不match则会抛出panic)|
下面的表达式可以返回一个可选的bool值:
可选的bool返回值的意义 | 忽略可选值会影响程序的行为? | |
---|---|---|
map element access | map中是否包含要 | No |
channel value receive | 在channel关闭前收到的值是否已发出 | No |
type assertion | 接口的动态类型是否符合asserted type | Yes |
(当可选值被忽略时,如果类型不match则会抛出panic)|
使用channel机制永远阻塞当前goroutine的方法
下面的方法都可以永远阻塞当前的goroutine:
1、receive from a channel which no values will be sent to
123
<-make(chan struct{}) // or<-make(<-chan struct{})
2、send value to a channel which no ones will receive values from
123
make(chan struct{}) <- struct{}{}// ormake(chan<- struct{}) <- struct{}{}
3、receive value from a nil channel
1
<-chan struct{}(nil)
4、send value to a nil channel
1
chan struct{}(nil) <- struct{}{}
5、use a bare select block
1
select{}
下面的方法都可以永远阻塞当前的goroutine:
1、receive from a channel which no values will be sent to
|
|
2、send value to a channel which no ones will receive values from
|
|
3、receive value from a nil channel
|
|
4、send value to a nil channel
|
|
5、use a bare select block
|
|
连接字符串的几种方法
下面几种方法都可以连接字符串(译者注:不考虑性能):
1、使用+
连接字符串。如果连接的字符串少于6个,官方的编译器会对此优化,所以通常使用+
简便而有效。
2、使用strings
包中的strings.Join连接字符串。
3、使用fmt
包中的fmt.Sprintf
, fmt.Sprint
和 fmt.Sprintln
连接字符串。这三个方法可以将任意的类型连接成字符串。fmt.Sprintln
会在字符串之间加空格,在字符串尾部加新的换行符。如果两个值中的至少一个不是字符串,fmt.Sprint
会在它们之间加空格。
4、包bytes
的Buffer
类型(或者内建函数copy
)可以用来构建 byte slice, byte slice可以方便地转换成字符串。
下面几种方法都可以连接字符串(译者注:不考虑性能):
1、使用+
连接字符串。如果连接的字符串少于6个,官方的编译器会对此优化,所以通常使用+
简便而有效。
2、使用strings
包中的strings.Join连接字符串。
3、使用fmt
包中的fmt.Sprintf
, fmt.Sprint
和 fmt.Sprintln
连接字符串。这三个方法可以将任意的类型连接成字符串。fmt.Sprintln
会在字符串之间加空格,在字符串尾部加新的换行符。如果两个值中的至少一个不是字符串,fmt.Sprint
会在它们之间加空格。
4、包bytes
的Buffer
类型(或者内建函数copy
)可以用来构建 byte slice, byte slice可以方便地转换成字符串。