這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
目錄 [−]
- 各種類型複製的時候的花費
- 可使用內建函數的類型 (len、cap、close、delete、make)
- 內建容器類型的值比較
- 組合類別型T{...}的值比較
- 零值是nil的類型
- 編譯時間被執行的函數
- 不能被定址的值
- 不支援比較的類型
- 可命名的原始碼元素
- 命名的原始碼元素可以使用 ()分組聲明
- 可以在函數內外聲明的原始碼元素
- 可以返回一個可選bool傳回值的運算式
- 使用channel機制永遠阻塞當前goroutine的方法
- 連接字串的幾種方法
原文: Golang Summaries by TapirLiu
本文是由TapirLiu總結的Golang中的一些知識點,對於深入學習Golang很有協助,所以我特意翻譯了一下。
各種類型複製的時候的花費
本區段標頭也可以叫做“各種類型的值的大小” (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
函數參數的類型也叫做容器類型。
內建容器類型的值比較
假定容器的值可定址(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 ) |
零值是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 |
這些類型的零值的大小和上面類型的大小保持一致。
編譯時間被執行的函數
如果函數在編譯時間被執行,那麼它的傳回值是常量。
Function |
傳回值 |
編譯時間便計算? |
unsafe.Sizeof |
uintptr |
Yes, 總是 |
unsafe.Alignof |
unsafe.Offsetof |
len |
int |
有時候是 Go 規範中講到:
- 如果s是字串常量,則
len(s) 是常量.
- 如果s是數組或者是數組指標,則
len(s) 是常量.
|
cap |
real |
float64 (預設類型) |
有時候是 Go 規範中講到: 如果s 是複數常量,則real(s) 和imag(s) 是常量. |
imag |
complex |
complex128 (預設類型) |
有時候是 Go 規範中講到: 如果sr 和si 都是常量,則complex(sr, si) 是常量. |
不能被定址的值
下面的值不能被定址(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。
可命名的原始碼元素
下面的原始碼元素可以命名,名稱必須是 Identifier
|
可以使用 _ 做名稱? |
package |
No |
import |
Yes |
type |
Yes |
variable |
Yes |
constant |
Yes |
function |
Yes |
label |
Yes |
命名的原始碼元素可以使用 ()
分組聲明
下面的類型可以使用()
分組生命
- import
- type
- variable
- constant
函數和標籤(label)不能使用()
分組聲明。
可以在函數內外聲明的原始碼元素
下面的類型可以聲明在函數內,也可以聲明在函數外:
import
必須在其它元素的聲明的前面(package
語句的後面)。
函數在其它函數的外面聲明。(譯者注:函數變數/匿名函數可以在函數內聲明)
標籤(label)必須聲明在函數內。
可以返回一個可選bool傳回值的運算式
下面的運算式可以返回一個可選的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
1 2 3 |
<-make(chan struct{}) // or <-make(<-chan struct{}) |
2、send value to a channel which no ones will receive values from
1 2 3 |
make(chan struct{}) <- struct{}{} // or make(chan<- struct{}) <- struct{}{} |
3、receive value from a nil channel
4、send value to a nil channel
1 |
chan struct{}(nil) <- struct{}{} |
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可以方便地轉換成字串。