我們將在這個部分講解有關布爾型、數字型和字符型的相關知識。
表達式是一種特定的類型的值,它可以由其它的值以及運算符組合而成。每個類型都定義了可以和自己結合的運算符集合,如果你使用了不在這個集合中的運算符,則會在編譯時獲得編譯錯誤。
一元運算符只可以用于一個值的操作(作為后綴),而二元運算符則可以和兩個值或者操作數結合(作為中綴)。
只有兩個類型相同的值才可以和二元運算符結合,另外要注意的是,Go 是強類型語言,因此不會進行隱式轉換,任何不同類型之間的轉換都必須顯式說明(第 4.2 節)。Go 不存在像 C 和 Java 那樣的運算符重載,表達式的解析順序是從左至右。
你可以在第 4.5.3 節找到有關運算符優先級的相關信息,優先級越高的運算符在條件相同的情況下將被優先執行。但是你可以通過使用括號將其中的表達式括起來,以人為地提升某個表達式的運算優先級。
## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#451-布爾類型-bool)4.5.1 布爾類型 bool
一個簡單的例子:`var b bool = true`。
布爾型的值只可以是常量 true 或者 false。
兩個類型相同的值可以使用相等?`==`?或者不等?`!=`?運算符來進行比較并獲得一個布爾型的值。
當相等運算符兩邊的值是完全相同的值的時候會返回 true,否則返回 false,并且只有在兩個的值的類型相同的情況下才可以使用。
示例:
~~~
var aVar = 10
aVar == 5 -> false
aVar == 10 -> true
~~~
當不等運算符兩邊的值是不同的時候會返回 true,否則返回 false。
示例:
~~~
var aVar = 10
aVar != 5 -> true
aVar != 10 -> false
~~~
Go 對于值之間的比較有非常嚴格的限制,只有兩個類型相同的值才可以進行比較,如果值的類型是接口(interface,第 11 章),它們也必須都實現了相同的接口。如果其中一個值是常量,那么另外一個值的類型必須和該常量類型相兼容的。如果以上條件都不滿足,則其中一個值的類型必須在被轉換為和另外一個值的類型相同之后才可以進行比較。
布爾型的常量和變量也可以通過和邏輯運算符(非?`!`、和?`&&`、或?`||`)結合來產生另外一個布爾值,這樣的邏輯語句就其本身而言,并不是一個完整的 Go 語句。
邏輯值可以被用于條件結構中的條件語句(第 5 章),以便測試某個條件是否滿足。另外,和?`&&`、或?`||`?與相等?`==`?或不等?`!=`?屬于二元運算符,而非?`!`?屬于一元運算符。在接下來的內容中,我們會使用 T 來代表條件符合的語句,用 F 來代表條件不符合的語句。
Go 語言中包含以下邏輯運算符:
非運算符:`!`
~~~
!T -> false
!F -> true
~~~
非運算符用于取得和布爾值相反的結果。
和運算符:`&&`
~~~
T && T -> true
T && F -> false
F && T -> false
F && F -> false
~~~
只有當兩邊的值都為 true 的時候,和運算符的結果才是 true。
或運算符:`||`
~~~
T || T -> true
T || F -> true
F || T -> true
F || F -> false
~~~
只有當兩邊的值都為 false 的時候,或運算符的結果才是 false,其中任意一邊的值為 true 就能夠使得該表達式的結果為 true。
在 Go 語言中,&& 和 || 是具有快捷性質的運算符,當運算符左邊表達式的值已經能夠決定整個表達式的值的時候(&& 左邊的值為 false,|| 左邊的值為 true),運算符右邊的表達式將不會被執行。利用這個性質,如果你有多個條件判斷,應當將計算過程較為復雜的表達式放在運算符的右側以減少不必要的運算。
利用括號同樣可以升級某個表達式的運算優先級。
在格式化輸出時,你可以使用?`%t`?來表示你要輸出的值為布爾型。
布爾值(以及任何結果為布爾值的表達式)最常用在條件結構的條件語句中,例如:if、for 和 switch 結構(第 5 章)。
對于布爾值的好的命名能夠很好地提升代碼的可讀性,例如以?`is`?或者?`Is`?開頭的`isSorted`、`isFinished`、`isVisivle`,使用這樣的命名能夠在閱讀代碼的獲得閱讀正常語句一樣的良好體驗,例如標準庫中的?`unicode.IsDigit(ch)`(第 4.5.5 節)。
## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#452-數字類型)4.5.2 數字類型
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4521-整型-int-和浮點型-float)4.5.2.1 整型 int 和浮點型 float
Go 語言支持整型和浮點型數字,并且原生支持復數,其中位的運算采用補碼(詳情參見?[二的補碼](http://en.wikipedia.org/wiki/Two's_complement)?頁面)。
Go 也有基于架構的類型,例如:int、uint 和 uintptr。
這些類型的長度都是根據運行程序所在的操作系統類型所決定的:
* `int`?和?`uint`?在 32 位操作系統上,它們均使用 32 位(4 個字節),在 64 位操作系統上,它們均使用 64 位(8 個字節)。
* `uintptr`?的長度被設定為足夠存放一個指針即可。
Go 語言中沒有 float 類型。
與操作系統架構無關的類型都有固定的大小,并在類型的名稱中就可以看出來:
整數:
* int8(-128 -> 127)
* int16(-32768 -> 32767)
* int32(-2,147,483,648 -> 2,147,483,647)
* int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)
無符號整數:
* uint8(0 -> 255)
* uint16(0 -> 65,535)
* uint32(0 -> 4,294,967,295)
* uint64(0 -> 18,446,744,073,709,551,615)
浮點型(IEEE-754 標準):
* float32(+- 1e-45 -> +- 3.4 * 1e38)
* float64(+- 5 * 1e-324 -> 107 * 1e308)
int 型是計算最快的一種類型。
整型的零值為 0,浮點型的零值為 0.0。
float32 精確到小數點后 7 位,float64 精確到小數點后 15 位。由于精確度的緣故,你在使用?`==`?或者?`!=`?來比較浮點數時應當非常小心。你最好在正式使用前測試對于精確度要求較高的運算。
你應該盡可能地使用 float64,因為?`math`?包中所有有關數學運算的函數都會要求接收這個類型。
你可以通過增加前綴 0 來表示 8 進制數(如:077),增加前綴 0x 來表示 16 進制數(如:0xFF),以及使用 e 來表示 10 的連乘(如: 1e3 = 1000,或者 6.022e23 = 6.022 x 1e23)。
你可以使用?`a := uint64(0)`?來同時完成類型轉換和賦值操作,這樣 a 的類型就是 uint64。
Go 中不允許不同類型之間的混合使用,但是對于常量的類型限制非常少,因此允許常量之間的混合使用,下面這個程序很好地解釋了這個現象(該程序無法通過編譯):
示例 4.8?[type_mixing.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/type_mixing.go)
~~~
package main
func main() {
var a int
var b int32
a = 15
b = a + a // 編譯錯誤
b = b + 5 // 因為 5 是常量,所以可以通過編譯
}
~~~
如果你嘗試編譯該程序,則將得到編譯錯誤?`cannot use a + a (type int) as type int32 in assignment`。
同樣地,int16 也不能夠被隱式轉換為 int32。
下面這個程序展示了通過顯示轉換來避免這個問題(第 4.2 節)。
示例 4.9?[casting.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/casting.go)
~~~
package main
import "fmt"
func main() {
var n int16 = 34
var m int32
// compiler error: cannot use n (type int16) as type int32 in assignment
//m = n
m = int32(n)
fmt.Printf("32 bit int is: %d\n", m)
fmt.Printf("16 bit int is: %d\n", n)
}
~~~
輸出:
~~~
32 bit int is: 34
16 bit int is: 34
~~~
**格式化說明符**
在格式化字符串里,`%d`?用于格式化整數(`%x`?和?`%X`?用于格式化 16 進制表示的數字),`%g`?用于格式化浮點型(`%f`?輸出浮點數,`%e`?輸出科學計數表示法),`%0d`?用于規定輸出定長的整數,其中開頭的數字 0 是必須的。
`%n.mg`?用于表示數字 n 并精確到小數點后 m 位,除了使用 g 之外,還可以使用 e 或者 f,例如:使用格式化字符串`%5.2e`?來輸出 3.4 的結果為?`3.40e+00`。
**數字值轉換**
當進行類似?`a32bitInt = int32(a32Float)`?的轉換時,小數點后的數字將被丟棄。這種情況一般發生當從取值范圍較大的類型轉換為取值范圍較小的類型時,或者你可以寫一個專門用于處理類型轉換的函數來確保沒有發生精度的丟失。下面這個例子展示如何安全地從 int 型轉換為 int8:
~~~
func Uint8FromInt(n int) (uint8, error) {
if 0 <= n && n <= math.MaxUint8 { // conversion is safe
return uint8(n), nil
}
return 0, fmt.Errorf("%d is out of the uint8 range", n)
}
~~~
或者安全地從 float64 轉換為 int:
~~~
func IntFromFloat64(x float64) int {
if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
whole, fraction := math.Modf(x)
if fraction >= 0.5 {
whole++
}
return int(whole)
}
panic(fmt.Sprintf("%g is out of the int32 range", x))
}
~~~
不過如果你實際存的數字超出你要轉換到的類型的取值范圍的話,則會引發 panic(第 13.2 節)。
**問題 4.1**?int 和 int64 是相同的類型嗎?
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4522-復數)4.5.2.2 復數
Go 擁有以下復數類型:
~~~
complex64 (32 位實數和虛數)
complex128 (64 位實數和虛數)
~~~
復數使用?`re+imI`?來表示,其中?`re`?代表實數部分,`im`?代表虛數部分,I 代表根號負 1。
示例:
~~~
var c1 complex64 = 5 + 10i
fmt.Printf("The value is: %v", c1)
// 輸出: 5 + 10i
~~~
如果?`re`?和?`im`?的類型均為 float32,那么類型為 complex64 的復數 c 可以通過以下方式來獲得:
~~~
c = complex(re, im)
~~~
函數?`real(c)`?和?`imag(c)`?可以分別獲得相應的實數和虛數部分。
在使用格式化說明符時,可以使用?`%v`?來表示復數,但當你希望只表示其中的一個部分的時候需要使用?`%f`。
復數支持和其它數字類型一樣的運算。當你使用等號?`==`?或者不等號?`!=`?對復數進行比較運算時,注意對精確度的把握。`cmath`?包中包含了一些操作復數的公共方法。如果你對內存的要求不是特別高,最好使用 complex128 作為計算類型,因為相關函數都使用這個類型的參數。
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4523-位運算)4.5.2.3 位運算
位運算只能用于整數類型的變量,且需當它們擁有等長位模式時。
`%b`?是用于表示位的格式化標識符。
**二元運算符**
* 按位與?`&`:
對應位置上的值經過和運算結果,具體參見和運算符,第 4.5.1 節,并將 T(true)替換為 1,將 F(false)替換為 0
~~~
1 & 1 -> 1
1 & 0 -> 0
0 & 1 -> 0
0 & 0 -> 0
~~~
* 按位或?`|`:
對應位置上的值經過或運算結果,具體參見或運算符,第 4.5.1 節,并將 T(true)替換為 1,將 F(false)替換為 0
~~~
1 | 1 -> 1
1 | 0 -> 1
0 | 1 -> 1
0 | 0 -> 0
~~~
* 按位異或?`^`:
對應位置上的值根據以下規則組合:
~~~
1 ^ 1 -> 0
1 ^ 0 -> 1
0 ^ 1 -> 1
0 ^ 0 -> 0
~~~
* 位清除?`&^`:將指定位置上的值設置為 0。
**一元運算符**
* 按位補足?`^`:
該運算符與異或運算符一同使用,即?`m^x`,對于無符號 x 使用“全部位設置為 1”,對于有符號 x 時使用?`m=-1`。例如:
~~~
^2 = ^10 = -01 ^ 10 = -11
~~~
* 位左移?`<<`:
* 用法:`bitP << n`。
* `bitP`?的位向左移動 n 位,右側空白部分使用 0 填充;如果 n 等于 2,則結果是 2 的相應倍數,即 2 的 n 次方。例如:
~~~
1 << 10 // 等于 1 KB
1 << 20 // 等于 1 MB
1 << 30 // 等于 1 GB
~~~
* 位右移?`>>`:
* 用法:`bitP >> n`。
* `bitP`?的位向右移動 n 位,左側空白部分使用 0 填充;如果 n 等于 2,則結果是當前值除以 2 的 n 次方。
當希望把結果賦值給第一個操作數時,可以簡寫為?`a <<= 2`?或者?`b ^= a & 0xffffffff`。
**位左移常見實現存儲單位的用例**
使用位左移與 iota 計數配合可優雅地實現存儲單位的常量枚舉:
~~~
type ByteSize float64
const (
_ = iota // 通過賦值給空白標識符來忽略值
KB ByteSize = 1<<(10*iota)
MB
GB
TB
PB
EB
ZB
YB
)
~~~
**在通訊中使用位左移表示標識的用例**
~~~
type BitFlag int
const (
Active BitFlag = 1 << iota // 1 << 0 == 1
Send // 1 << 1 == 2
Receive // 1 << 2 == 4
)
flag := Active | Send // == 3
~~~
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4524-邏輯運算符)4.5.2.4 邏輯運算符
Go 中擁有以下邏輯運算符:`==`、`!=`(第 4.5.1 節)、`<`、`<=`、`>`、`>=`。
它們之所以被稱為邏輯運算符是因為它們的運算結果總是為布爾值?`bool`。例如:
~~~
b3:= 10 > 5 // b3 is true
~~~
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4525-算術運算符)4.5.2.5 算術運算符
常見可用于整數和浮點數的二元運算符有?`+`、`-`、`*`?和?`/`。
(相對于一般規則而言,Go 在進行字符串拼接時允許使用對運算符?`+`?的重載,但 Go 本身不允許開發者進行自定義的運算符重載)
`/`?對與整數運算而言,結果依舊為整數,例如:`9 / 4 -> 2`。
取余運算符只能作用于整數:`9 % 4 -> 1`。
整數除以 0 可能導致程序崩潰,將會導致運行時的恐慌狀態(如果除以 0 的行為在編譯時就能被捕捉到,則會引發編譯錯誤);第 13 章將會詳細講解如何正確地處理此類情況。
浮點數除以 0.0 會返回一個無窮盡的結果,使用?`+Inf`?表示。
**練習 4.4**?嘗試編譯?[divby0.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/exercises/chapter_4/divby0.go)。
你可以將語句?`b = b + a`?簡寫為?`b+=a`,同樣的寫法也可用于?`-=`、`*=`、`/=`、`%=`。
對于整數和浮點數,你可以使用一元運算符?`++`(遞增)和?`--`(遞減),但只能用于后綴:
~~~
i++ -> i += 1 -> i = i + 1
i-- -> i -= 1 -> i = i - 1
~~~
同時,帶有?`++`?和?`--`?的只能作為語句,而非表達式,因此?`n = i++`?這種寫法是無效的,其它像?`f(i++)`?或者`a[i]=b[i++]`?這些可以用于 C、C++ 和 Java 中的寫法在 Go 中也是不允許的。
在運算時?**溢出**?不會產生錯誤,Go 會簡單地將超出位數拋棄。如果你需要范圍無限大的整數或者有理數(意味著只被限制于計算機內存),你可以使用標準庫中的?`big`?包,該包提供了類似?`big.Int`?和?`big.Rat`?這樣的類型(第 9.4 節)。
### [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#4526-隨機數)4.5.2.6 隨機數
一些像游戲或者統計學類的應用需要用到隨機數。`rand`?包實現了偽隨機數的生成。
示例 4.10?[random.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/random.go)?演示了如何生成 10 個非負隨機數:
~~~
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
for i := 0; i < 10; i++ {
a := rand.Int()
fmt.Printf("%d / ", a)
}
for i := 0; i < 5; i++ {
r := rand.Intn(8)
fmt.Printf("%d / ", r)
}
fmt.Println()
timens := int64(time.Now().Nanosecond())
rand.Seed(timens)
for i := 0; i < 10; i++ {
fmt.Printf("%2.2f / ", 100*rand.Float32())
}
}
~~~
可能的輸出:
~~~
816681689 / 1325201247 / 623951027 / 478285186 / 1654146165 /
1951252986 / 2029250107 / 762911244 / 1372544545 / 591415086 / / 3 / 0 / 6 / 4 / 2 /22.10
/ 65.77 / 65.89 / 16.85 / 75.56 / 46.90 / 55.24 / 55.95 / 25.58 / 70.61 /
~~~
函數?`rand.Float32`?和?`rand.Float64`?返回介于 [0.0, 1.0) 之間的偽隨機數,其中包括 0.0 但不包括 1.0。函數?`rand.Intn`返回介于 [0, n) 之間的偽隨機數。
你可以使用?`Seed(value)`?函數來提供偽隨機數的生成種子,一般情況下都會使用當前時間的納秒級數字(第 4.8 節)。
## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#453-運算符與優先級)4.5.3 運算符與優先級
有些運算符擁有較高的優先級,二元運算符的運算方向均是從左至右。下表列出了所有運算符以及它們的優先級,由上至下代表優先級由高到低:
~~~
優先級 運算符
7 ^ !
6 * / % << >> & &^
5 + - | ^
4 == != < <= >= >
3 <-
2 &&
1 ||
~~~
當然,你可以通過使用括號來臨時提升某個表達式的整體運算優先級。
## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#454-類型別名)4.5.4 類型別名
當你在使用某個類型時,你可以給它起另一個名字,然后你就可以在你的代碼中使用新的名字(用于簡化名稱或解決名稱沖突)。
在?`type TZ int`?中,TZ 就是 int 類型的新名稱(用于表示程序中的時區),然后就可以使用 TZ 來操作 int 類型的數據。
示例 4.11?[type.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/type.go)
~~~
package main
import "fmt"
type TZ int
func main() {
var a, b TZ = 3, 4
c := a + b
fmt.Printf("c has the value: %d", c) // 輸出:c has the value: 7
}
~~~
實際上,類型別名得到的新類型并非和原類型完全相同,新類型不會擁有原類型所附帶的方法(第 10 章);TZ 可以自定義一個方法用來輸出更加人性化的時區信息。
**練習 4.5**?定義一個?`string`?的類型別名?`Rope`,并聲明一個該類型的變量。
## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.5.md#455-字符類型)4.5.5 字符類型
嚴格來說,這并不是 Go 語言的一個類型,字符只是整數的特殊用例。`byte`?類型是?`uint8`?的別名,對于只占用 1 個字節的傳統 ASCII 編碼的字符來說,完全沒有問題。例如:`var ch byte = 'A'`;字符使用單引號括起來。
在 ASCII 碼表中,A 的值是 65,而使用 16 進制表示則為 41,所以下面的寫法是等效的:
~~~
var ch byte = 65 或 var ch byte = '\x41'
~~~
(`\x`?總是緊跟著長度為 2 的 16 進制數)
另外一種可能的寫法是?`\`?后面緊跟著長度為 3 的十進制數,例如:`\377`。
不過 Go 同樣支持 Unicode(UTF-8),因此字符同樣稱為 Unicode 代碼點或者 runes,并在內存中使用 int 來表示。在文檔中,一般使用格式 U+hhhh 來表示,其中 h 表示一個 16 進制數。其實?`rune`?也是 Go 當中的一個類型,并且是?`int32`的別名。
在書寫 Unicode 字符時,需要在 16 進制數之前加上前綴?`\u`?或者?`\U`。
因為 Unicode 至少占用 2 個字節,所以我們使用?`int16`?或者?`int`?類型來表示。如果需要使用到 4 字節,則會加上?`\U`前綴;前綴?`\u`?則總是緊跟著長度為 4 的 16 進制數,前綴?`\U`?緊跟著長度為 8 的 16 進制數。
示例 4.12?[char.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/char.go)
~~~
var ch int = '\u0041'
var ch2 int = '\u03B2'
var ch3 int = '\U00101234'
fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer
fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character
fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes
fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point
~~~
輸出:
~~~
65 - 946 - 1053236
A - β - r
41 - 3B2 - 101234
U+0041 - U+03B2 - U+101234
~~~
格式化說明符?`%c`?用于表示字符;當和字符配合使用時,`%v`?或?`%d`?會輸出用于表示該字符的整數;`%U`?輸出格式為 U+hhhh 的字符串(另一個示例見第 5.4.4 節)。
包?`unicode`?包含了一些針對測試字符的非常有用的函數(其中?`ch`?代表字符):
* 判斷是否為字母:`unicode.IsLetter(ch)`
* 判斷是否為數字:`unicode.IsDigit(ch)`
* 判斷是否為空白符號:`unicode.IsSpace(ch)`
這些函數返回一個布爾值。包?`utf8`?擁有更多與 rune 相關的函數。
(?**譯者注:關于類型的相關講解,可參考視頻教程 《Go編程基礎》 第 3 課:[類型與變量](https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture3.md)**?)
- 前言
- 第一部分:學習 Go 語言
- 第1章:Go 語言的起源,發展與普及
- 1.1 起源與發展
- 1.2 語言的主要特性與發展的環境和影響因素
- 第2章:安裝與運行環境
- 2.1 平臺與架構
- 2.2 Go 環境變量
- 2.3 在 Linux 上安裝 Go
- 2.4 在 Mac OS X 上安裝 Go
- 2.5 在 Windows 上安裝 Go
- 2.6 安裝目錄清單
- 2.7 Go 運行時(runtime)
- 2.8 Go 解釋器
- 第3章:編輯器、集成開發環境與其它工具
- 3.1 Go 開發環境的基本要求
- 3.2 編輯器和集成開發環境
- 3.3 調試器
- 3.4 構建并運行 Go 程序
- 3.5 格式化代碼
- 3.6 生成代碼文檔
- 3.7 其它工具
- 3.8 Go 性能說明
- 3.9 與其它語言進行交互
- 第二部分:語言的核心結構與技術
- 第4章:基本結構和基本數據類型
- 4.1 文件名、關鍵字與標識符
- 4.2 Go 程序的基本結構和要素
- 4.3 常量
- 4.4 變量
- 4.5 基本類型和運算符
- 4.6 字符串
- 4.7 strings 和 strconv 包
- 4.8 時間和日期
- 4.9 指針
- 第5章:控制結構
- 5.1 if-else 結構
- 5.2 測試多返回值函數的錯誤
- 5.3 switch 結構
- 5.4 for 結構
- 5.5 Break 與 continue
- 5.6 標簽與 goto
- 第6章:函數(function)
- 6.1 介紹
- 6.2 函數參數與返回值
- 6.3 傳遞變長參數
- 6.4 defer 和追蹤
- 6.5 內置函數
- 6.6 遞歸函數
- 6.7 將函數作為參數
- 6.8 閉包
- 6.9 應用閉包:將函數作為返回值
- 6.10 使用閉包調試
- 6.11 計算函數執行時間
- 6.12 通過內存緩存來提升性能
- 第7章:數組與切片
- 7.1 聲明和初始化
- 7.2 切片
- 7.3 For-range 結構
- 7.4 切片重組(reslice)
- 7.5 切片的復制與追加
- 7.6 字符串、數組和切片的應用
- 第8章:Map
- 8.1 聲明、初始化和 make
- 8.2 測試鍵值對是否存在及刪除元素
- 8.3 for-range 的配套用法
- 8.4 map 類型的切片
- 8.5 map 的排序
- 8.6 將 map 的鍵值對調
- 第9章:包(package)
- 9.1 標準庫概述
- 9.2 regexp 包
- 9.3 鎖和 sync 包
- 9.4 精密計算和 big 包
- 9.5 自定義包和可見性
- 9.6 為自定義包使用 godoc
- 9.7 使用 go install 安裝自定義包
- 9.8 自定義包的目錄結構、go install 和 go test
- 9.9 通過 Git 打包和安裝
- 9.10 Go 的外部包和項目
- 9.11 在 Go 程序中使用外部庫
- 第10章:結構(struct)與方法(method)
- 10.1 結構體定義
- 10.2 使用工廠方法創建結構體實例
- 10.3 使用自定義包中的結構體
- 10.4 帶標簽的結構體
- 10.5 匿名字段和內嵌結構體
- 10.6 方法
- 10.8 垃圾回收和 SetFinalizer
- 第11章:接口(interface)與反射(reflection)
- 11.1 接口是什么
- 11.2 接口嵌套接口
- 11.3 類型斷言:如何檢測和轉換接口變量的類型
- 11.4 類型判斷:type-switch
- 11.5 測試一個值是否實現了某個接口
- 11.6 使用方法集與接口
- 11.7 第一個例子:使用 Sorter 接口排序
- 11.8 第二個例子:讀和寫
- 11.9 空接口
- 11.10 反射包
- 第三部分:Go 高級編程
- 第12章 讀寫數據
- 12.1 讀取用戶的輸入
- 12.2 文件讀寫
- 12.3 文件拷貝
- 12.4 從命令行讀取參數
- 12.5 用buffer讀取文件
- 12.6 用切片讀寫文件
- 12.7 用 defer 關閉文件
- 12.8 使用接口的實際例子:fmt.Fprintf
- 12.9 Json 數據格式
- 12.10 XML 數據格式
- 12.11 用 Gob 傳輸數據
- 12.12 Go 中的密碼學
- 第13章 錯誤處理與測試
- 13.1 錯誤處理
- 13.2 運行時異常和 panic
- 13.3 從 panic 中恢復(Recover)
- 13.4 自定義包中的錯誤處理和 panicking
- 13.5 一種用閉包處理錯誤的模式
- 13.6 啟動外部命令和程序
- 13.7 Go 中的單元測試和基準測試
- 13.8 測試的具體例子
- 13.9 用(測試數據)表驅動測試
- 13.10 性能調試:分析并優化 Go 程序
- 第14章:協程(goroutine)與通道(channel)
- 14.1 并發、并行和協程
- 14.2 使用通道進行協程間通信
- 14.3 協程同步:關閉通道-對阻塞的通道進行測試
- 14.4 使用 select 切換協程
- 14.5 通道,超時和計時器(Ticker)
- 14.6 協程和恢復(recover)
- 第15章:網絡、模版與網頁應用
- 15.1 tcp服務器
- 15.2 一個簡單的web服務器
- 15.3 訪問并讀取頁面數據
- 15.4 寫一個簡單的網頁應用
- 第四部分:實際應用
- 第16章:常見的陷阱與錯誤
- 16.1 誤用短聲明導致變量覆蓋
- 16.2 誤用字符串
- 16.3 發生錯誤時使用defer關閉一個文件
- 16.5 不需要將一個指向切片的指針傳遞給函數
- 16.6 使用指針指向接口類型
- 16.7 使用值類型時誤用指針
- 16.8 誤用協程和通道
- 16.9 閉包和協程的使用
- 16.10 糟糕的錯誤處理
- 第17章:模式
- 17.1 關于逗號ok模式
- 第18章:出于性能考慮的實用代碼片段
- 18.1 字符串
- 18.2 數組和切片
- 18.3 映射
- 18.4 結構體
- 18.5 接口
- 18.6 函數
- 18.7 文件
- 18.8 協程(goroutine)與通道(channel)
- 18.9 網絡和網頁應用
- 18.10 其他
- 18.11 出于性能考慮的最佳實踐和建議
- 附錄