ch3,ch3-01 review

This commit is contained in:
chai2010
2015-12-27 15:13:12 +08:00
parent 7c96bf43e6
commit 6978661750
21 changed files with 67 additions and 63 deletions

View File

@@ -1,20 +1,20 @@
## 3.1. 整型
Go語言的數值類型包括幾種不同大小的整形數, 浮點數, 和複數. 每種數值類型都決定了對應的大小范圍和是否正負符號. 讓我們先從整形數類型開始介紹.
Go語言的數值類型包括幾種不同大小的整形數浮點數和複數每種數值類型都決定了對應的大小范圍和是否支持正負符號讓我們先從整形數類型開始介紹
Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int16, int32int64截然不同大小的有符號整形數類型, 分别對應 8, 16, 32, 64 bit 大小的有符號整形數, 與此對應的是 uint8, uint16, uint32, 和 uint64 四種無符號整形數類型.
Go語言同時提供了有符號和無符號類型的整數運算這里有int8int16int32int64四種截然不同大小的有符號整形數類型分别對應8、16、32、64bit大小的有符號整形數與此對應的是uint8uint16uint32uint64四種無符號整形數類型
這里還有兩種對應特定平颱最天然或最有效率的大小有符號和無符號整數int和uint; 其中int是應用最廣泛的數值類型. 這兩種類型都有同樣的大小, 32 或 64 bit, 但是我們不能對此做任何的假設; 因爲不同的編譯器在相同的硬件平上可能産生不同的大小.
這里還有兩種一般對應特定CPU平台機器字大小有符號和無符號整數int和uint其中int是應用最廣泛的數值類型這兩種類型都有同樣的大小32或64bit但是我們不能對此做任何的假設因爲不同的編譯器卽使在相同的硬件平上可能産生不同的大小
字符rune類型是和int32等價的類型, 通常用於表示一個Unicode碼點. 這兩個名稱可以互換使用. 同樣byte也是uint8類型的等價類型, byte類型用於強調數值是一個原始的數據而不是一個小的整數.
Unicode字符rune類型是和int32等價的類型通常用於表示一個Unicode碼點這兩個名稱可以互換使用同樣byte也是uint8類型的等價類型byte類型一般用於強調數值是一個原始的數據而不是一個小的整數
好, 還有一無符號的整數類型 uintptr, 沒有指定具體的bit大小但是足以容納指針. uintptr 類型隻有在底層編程是才需要, 特别是Go語言和C函數庫或操作繫統相交互的地方. 我們將在第十三章的 unsafe 包相關部分看到類似的例子.
後,還有一無符號的整數類型uintptr沒有指定具體的bit大小但是足以容納指針uintptr類型隻有在底層編程是才需要特别是Go語言和C語言函數庫或操作繫統接口相交互的地方我們將在第十三章的unsafe包相關部分看到類似的例子
不管它們的大小, int, uint, 和 uintptr 是不同類型大小的兄弟類型. 其中 intint32 也是不同的類型, 卽使int的大小也是32bit, 在需要將int當作int32類型的地方需要一個顯式的類型轉換, 反之亦然.
不管它們的具體大小,intuintuintptr是不同類型的兄弟類型其中intint32也是不同的類型卽使int的大小也是32bit在需要將int當作int32類型的地方需要一個顯式的類型轉換操作,反之亦然
有符號數采用2的補碼形式表示, 也就是最高位用作符號位, 一個nbit的有符號數的值域是 `-2^(n-1)``(2^(n-1)) - 1`. 無符號整數的所有bit位都用於表示非負數, 值域是 0 到 `(2^n) - 1`. 例如, int8 的值域是 -128 到 127, 而 uint8 的值域是 0 到 255.
其中有符號數采用2的補碼形式表示也就是最高bit位用作表示符號位一個n-bit的有符號數的值域是從$$-2^{n-1}$$到$$2^{n-1}-1$$。無符號整數的所有bit位都用於表示非負數值域是0到$$2^n-1$$。例如int8類型整數的值域是-128到127而uint8類型整數的值域是從0到255
下面是Go中關於算術, 邏輯和比較的二元運算符按照先級遞減的順序的列表:
下面是Go語言中關於算術運算、邏輯運算和比較運算的二元運算符,它們按照先級遞減的順序的排列:
```
* / % << >> & &^
@@ -24,14 +24,13 @@ Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int1
||
```
二元運算符有五種優先級. 在同一優先級, 使用左優先結合律, 使用括號可以明確優先順序, 括號也可以用於提陞優先級, 例如 `mask & (1 << 28)`.
二元運算符有五種優先級在同一優先級使用左優先結合規則,但是使用括號可以明確優先順序,使用括號也可以用於提陞優先級例如`mask & (1 << 28)`
對於上表中前兩行的運算符, 例如 + 有一個相應的賦值結合運算符 +=, 可以用於簡化賦值語句.
對於上表中前兩行的運算符,例如+運算符還有一個與賦值結合的對應運算符+=可以用於簡化賦值語句
整數的算術運算符 +, -, *, 和 / 可以適用與整數, 浮點數和複數, 但是取模運算符 % 僅用於整數. 不同編程語言間, % 取模運算的行爲併不相同. 在Go語言中, % 取模運算符的符號和被取模數的符號總是一致的, 因此 `-5%3``-5%-3` 結果都是 -2.除法運算符 `/` 的行爲依賴於操作數是否爲整數, 因此 `5.0/4.0` 的結果是 1.25, 但是 5/4 的結果是 1, 因此整數除法會向着0方向截斷餘數.
整數的算術運算符+、-、`*``/`可以適用與整數浮點數和複數但是取模運算符%僅用於整數間的運算。對於不同編程語言%取模運算的行爲可能併不相同在Go語言中%取模運算符的符號和被取模數的符號總是一致的因此`-5%3``-5%-3`結果都是-2除法運算符`/`的行爲依賴於操作數是否爲全爲整數,比如`5.0/4.0`的結果是1.25但是5/4的結果是1因爲整數除法會向着0方向截斷餘數
如果一個算術運算的結果, 不管是有符號或者是無符號的, 如果需要更多的bit位才能表示, 就説明是溢出了. 超出的高位的bit位部分將被丟棄. 如果原始的數值是有符號類型, 那麽最終結果可能是負的, 如果最左邊的bit爲是1的話, 例如int8的例子:
如果一個算術運算的結果不管是有符號或者是無符號的如果需要更多的bit位才能正確表示的話就説明計算結果是溢出了。超出的高位的bit位部分將被丟棄。如果原始的數值是有符號類型而且最左邊的bit爲是1的話那麽最終結果可能是負的例如int8的例子
```Go
var u uint8 = 255
@@ -41,7 +40,7 @@ var i int8 = 127
fmt.Println(i, i+1, i*i) // "127 -128 1"
```
兩個相同的整數類型可以使用下面的二元比較運算符進行比較; 比較表達式的結果是布爾類型.
兩個相同的整數類型可以使用下面的二元比較運算符進行比較比較表達式的結果是布爾類型
```
== equal to
@@ -52,18 +51,18 @@ fmt.Println(i, i+1, i*i) // "127 -128 1"
>= greater than or equal to
```
事實上, 布爾型, 數字類型字符串 等基本類型都是可比較的, 也就是説兩個相同類型的值可以用 ==!= 進行比較. 此外, 整數, 浮點數和字符串可以根據比較結果排序. 許多其類型的值是不可比較, 因此也就是不可排序的. 對於我們遇到的每種類型, 我們需要保證規則是類似的.
事實上布爾型數字類型字符串等基本類型都是可比較的也就是説兩個相同類型的值可以用==!=進行比較。此外,整數、浮點數和字符串可以根據比較結果排序許多其類型的值可能是不可比較的,因此也就可能是不可排序的對於我們遇到的每種類型我們需要保證規則的一致性。
這里是一元的加法和減法運算符:
這里是一元的加法和減法運算符
```
+ 一元加法 (無效果)
- 負數
```
對於整數, +x 是 0+x 的簡寫, -x 是 0-x 的簡寫; 對於浮點數和複數, +x 就是 x, -x 則是 x 的負數.
對於整數+x是0+x的簡寫-x則是0-x的簡寫對於浮點數和複數+x就是x-x則是x 的負數
Go語言還提供了以下的bit位操作運算符, 前面4個操作運算符併不區分是有符號還是無符號數:
Go語言還提供了以下的bit位操作運算符前面4個操作運算符併不區分是有符號還是無符號數
```
& 位運算 AND
@@ -74,11 +73,9 @@ Go語言還提供了以下的bit位操作運算符, 前面4個操作運算符併
>> 右移
```
位操作運算符 `^` 作爲二元運算符時是按位異或(XOR), 當用作一元運算符時表示按位取反; 也就是説, 它返迴一個每個bit位都取反的數. 位操作運算符 `&^` 用於按位置零(AND NOT): 表達式 `z = x &^ y` 結果z的bit位1, 如果對應y中bit位爲1, 否則對應的bit位等於x相應的bit位的值.
位操作運算符`^`作爲二元運算符時是按位異或XOR當用作一元運算符時表示按位取反也就是説它返迴一個每個bit位都取反的數位操作運算符`&^`用於按位置零AND NOT表達式`z = x &^ y`結果z的bit位爲0如果對應y中bit位爲1的話,否則對應的bit位等於x相應的bit位的值
下面的代碼演示了如何使用位操作解釋uint8類型值的8個獨立的bit位. 它使用了 Printf 函數的 %b 參數打印二進製格式的數字; 其中 %08b 中08表示打印至少8個數字, 不足的前綴用0填充.
下面的代碼演示了如何使用位操作解釋uint8類型值的8個獨立的bit位。它使用了Printf函數的%b參數打印二進製格式的數字其中%08b中08表示打印至少8個字符寬度不足的前綴部分用0填充。
```Go
var x uint8 = 1<<1 | 1<<5
@@ -102,13 +99,13 @@ fmt.Printf("%08b\n", x<<1) // "01000100", the set {2, 6}
fmt.Printf("%08b\n", x>>1) // "00010001", the set {0, 4}
```
(6.5節給出了一個可以遠大於一個字節的整數集的實現.)
6.5節給出了一個可以遠大於一個字節的整數集的實現。)
x<<n x>>n 移位運算中, 決定了移位操作bit數部分必鬚是無符號數; 被操作的 x 數可以是有符號或無符號數. 算術上, 一個 x<<n 左移運算等價於乘以 2^n, 一個 x>>n 右移運算等價於除以 2^n.
`x<<n``x>>n`移位運算中決定了移位操作bit數部分必鬚是無符號數被操作的x數可以是有符號或無符號數算術上,一個`x<<n`左移運算等價於乘以$$2^n$$,一個`x>>n`右移運算等價於除以$$2^n$$。
左移運算用零填充右邊空缺的bit位, 無符號數的右移運算也是用0填充左邊空缺的bit位, 但是有符號數的右移運算會用符號位的值填充左邊空缺的bit位. 因爲這個原因, 最好用無符號運算, 這樣你可以將整數完全當作一個bit位模式處理.
左移運算用零填充右邊空缺的bit位無符號數的右移運算也是用0填充左邊空缺的bit位但是有符號數的右移運算會用符號位的值填充左邊空缺的bit位因爲這個原因最好用無符號運算這樣你可以將整數完全當作一個bit位模式處理
盡管Go提供了無符號數和運算, 卽使數值本身不可能出現負數我們還是傾向於使用有符號的int類型, 就是數組的長度那樣, 雖然使用 uint 似乎是一個更合理的選擇. 事實上, 內置的 len 函數返迴一個有符號的int, 我們可以像下面這個逆序循環那樣處理.
盡管Go語言提供了無符號數和運算卽使數值本身不可能出現負數我們還是傾向於使用有符號的int類型,就像數組的長度那樣雖然使用uint無符號類型似乎是一個更合理的選擇事實上內置的len函數返迴一個有符號的int我們可以像下面例子那樣處理逆序循環。
```Go
medals := []string{"gold", "silver", "bronze"}
@@ -117,13 +114,13 @@ for i := len(medals) - 1; i >= 0; i-- {
}
```
另一個選擇將是災難性的. 如果 len 返迴一個無符號數, 那麽 i 也將是無符號的 uint, 然後條件 i >= 0 則永遠爲眞. 在三次迭代之後, 也就是 i == 0 時, i-- 語句將不會産生 -1, 而是變成一個uint的最大值(可能是 2^64 - 1), 然後 medals[i] 表達式將發生運行時 panic 異常(§5.9), 也就是試圖訪問一個切片范圍以外的元素.
另一個選擇對於上面的例子來説將是災難性的如果len函數返迴一個無符號數那麽i也將是無符號的uint類型,然後條件`i >= 0`則永遠爲眞在三次迭代之後也就是`i == 0`時,i--語句將不會産生-1而是變成一個uint類型的最大值可能是$$2^64-1$$然後medals[i]表達式將發生運行時panic異常§5.9也就是試圖訪問一個slice范圍以外的元素
出於這個原因, 無符號數往往隻有在位運算或其它特殊的運算常見才會使用, 就像 bit 集合, 分形二進製文件格式, 或者是哈希和加密操作等. 它們通常併不用於僅僅是表達非負數量的場合.
出於這個原因無符號數往往隻有在位運算或其它特殊的運算場景才會使用就像bit集合、分析二進製文件格式或者是哈希和加密操作等它們通常併不用於僅僅是表達非負數量的場合
一般來説, 需要一個顯式的轉換將一個值從一種類型轉化位另一種類型, 併且算術和邏輯運算的二元操作中必鬚是相同的類型. 雖然這偶爾會導致很長的表達式, 但是它消除了所有類型相關的問題, 也使得程序容易理解.
一般來説需要一個顯式的轉換將一個值從一種類型轉化位另一種類型併且算術和邏輯運算的二元操作中必鬚是相同的類型雖然這偶爾會導致需要很長的表達式但是它消除了所有類型相關的問題,而且也使得程序容易理解
從其他類似場景下, 考慮下面這個代碼:
在很多場景,會遇到類似下面的代碼通用的錯誤:
```Go
var apples int32 = 1
@@ -131,19 +128,19 @@ var oranges int16 = 2
var compote int = apples + oranges // compile error
```
當嚐試編譯這三個語句時, 將産生一個錯誤信息:
當嚐試編譯這三個語句時將産生一個錯誤信息
```
invalid operation: apples + oranges (mismatched types int32 and int16)
```
這種類型不匹配的問題可以有幾種不同的方法脩複, 最常見方法是將它們都顯式轉型一個常見類型:
這種類型不匹配的問題可以有幾種不同的方法脩複最常見方法是將它們都顯式轉型一個常見類型
```Go
var compote = int(apples) + int(oranges)
```
如2.5節所述, 對於每種類型T, 類型轉換操作T(x)將x轉換T類型, 如果轉換允許的話. 許多 整形數之間的相互轉換併不會改變數值; 它們隻是告訴編譯器如何解釋這個值. 但是對於將一個大尺寸的整數類型轉一個小尺寸的整數類型, 或者是將一個浮點數轉整數, 可能會改變數值或丟失精度:
如2.5節所述對於每種類型T,如果轉換允許的話,類型轉換操作T(x)將x轉換T類型許多整形數之間的相互轉換併不會改變數值它們隻是告訴編譯器如何解釋這個值但是對於將一個大尺寸的整數類型轉一個小尺寸的整數類型或者是將一個浮點數轉整數可能會改變數值或丟失精度
```Go
f := 3.141 // a float64
@@ -153,16 +150,16 @@ f = 1.99
fmt.Println(int(f)) // "1"
```
浮點數到整數的轉換將丟失任何小數部分, 向數軸零方向截斷. 你應該避免操作目標類型表示范圍的數值類型轉換, 因爲截斷的行爲依賴於具體的實現:
浮點數到整數的轉換將丟失任何小數部分,然後向數軸零方向截斷你應該避免對可能會超出目標類型表示范圍的數值類型轉換因爲截斷的行爲可能依賴於具體的實現
```Go
f := 1e100 // a float64
i := int(f) // 結果依賴於具體實現
```
任何大小的整數字面值都可以用以0開始的八進製格式書寫, 例如 0666, 或用以0x或0X開頭的十六進製格式書寫, 例如 0xdeadbeef. 十六進製數字可以用大寫或小寫字母. 如今八進製數據通常用於POSIX操作繫統上的文件訪問權限標誌, 十六進製數字則更強調數字值的bit位模式.
任何大小的整數字面值都可以用以0開始的八進製格式書寫例如0666或用以0x或0X開頭的十六進製格式書寫例如0xdeadbeef十六進製數字可以用大寫或小寫字母如今八進製數據通常用於POSIX操作繫統上的文件訪問權限標誌十六進製數字則更強調數字值的bit位模式
當使用 fmt 包打印一個數值時, 我們可以用 %d, %o, 或 %x 控製輸出的進製格式, 就像下面的例子:
當使用fmt包打印一個數值時我們可以用%d、%o或%x參數控製輸出的進製格式就像下面的例子
```Go
o := 0666
@@ -173,18 +170,18 @@ fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x)
// 3735928559 deadbeef 0xdeadbeef 0XDEADBEEF
```
請註意 fmt 的兩個使用技巧. 通常 Printf 格式化字符串包含多個 % 參數時將對應相同數量的額外操作數, 但是 % 之後的 `[1]` 副詞告訴Printf函數再次使用第一個操作數. 第二, % 後的 `#` 副詞告訴 Printf 在用 %o, %x 或 %X 輸出時生成 0, 0x 或 0X前綴.
請註意fmt的兩個使用技巧通常Printf格式化字符串包含多個%參數時將會包含對應相同數量的額外操作數,但是%之後的`[1]`副詞告訴Printf函數再次使用第一個操作數。第二,%後的`#`副詞告訴Printf在用%o、%x或%X輸出時生成0、0x或0X前綴
字符面值通過一對單引號直接包含對應字符. 最簡單的例子是 ASCII 中類似 'a' 字符面值, 但是我們可以通過轉義的數值來表示任意的Unicode碼點對應的字符, 馬上將會看到例子.
字符面值通過一對單引號直接包含對應字符最簡單的例子是ASCII中類似'a'寫法的字符面值但是我們可以通過轉義的數值來表示任意的Unicode碼點對應的字符馬上將會看到這樣的例子
字符使用 `%c` 參數打印, 或者是 `%q` 參數打印帶單引號的字符:
字符使用`%c`參數打印或者是`%q`參數打印帶單引號的字符
```Go
ascii := 'a'
unicode := ''
unicode := ''
newline := '\n'
fmt.Printf("%d %[1]c %[1]q\n", ascii) // "97 a 'a'"
fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 ''"
fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 ''"
fmt.Printf("%d %[1]q\n", newline) // "10 '\n'"
```

View File

@@ -1,6 +1,6 @@
## 3.2. 浮點數
Go語言提供了兩種精度的浮點數, float32 和 float64. 它們的算術規范由 IEEE754 際標準定義, 該浮點數規范被所有現代的CPU支持.
Go語言提供了兩種精度的浮點數, float32 和 float64. 它們的算術規范由 IEEE754 際標準定義, 該浮點數規范被所有現代的CPU支持.
這些數值類型的范圍可以從很微小到很鉅大. 浮點數的范圍極限值可以在 matn 包找到. 常量 math.MaxFloat32 表示 float32 能表示的最大數值, 大約是 3.4e38, 對應的 math.MaxFloat64 常量大約是 1.8e308. 它們能表示的最小值近似分别是1.4e-45 和 4.9e-324.

View File

@@ -28,7 +28,7 @@
可以通過十六進製或八進製轉義在字符串面值包含任意的字節. 一個十六進製的轉義是 \xhh, 其中兩個h表示十六進製數字(大寫或小寫都可以). 一個八進製轉義是 \ooo, 包含三個八進製的o數字(0到7), 但是不能超過\377. 每一個單一的字節表達一個特定的值. 稍後我們將看到如何將一個Unicode碼點寫到字符串面值中.
一個原生的字符串面值形式是 `...`, 使用反引號 ``` 代替雙引號. 在原生的字符串面值中, 沒有轉義操作; 全部的內容都是字面的意思, 包含退格和換行, 因此一個程序中的原生字符串面值可能跨越多行. 唯一的特殊處理是是刪除迴車以保證在所有平上的值都是一樣的, 包括那些把迴車也放入文本文件的繫統.
一個原生的字符串面值形式是 `...`, 使用反引號 ``` 代替雙引號. 在原生的字符串面值中, 沒有轉義操作; 全部的內容都是字面的意思, 包含退格和換行, 因此一個程序中的原生字符串面值可能跨越多行. 唯一的特殊處理是是刪除迴車以保證在所有平上的值都是一樣的, 包括那些把迴車也放入文本文件的繫統.
原生字符串面值用於編寫正則表達式會很方便, 因爲正則表達式往往會包含很多反斜槓. 原生字符串面值同時廣泛應用於HTML模闆, JSON面值, 命令行提示信息, 以及那些需要擴展到多行的場景.

View File

@@ -1,7 +1,7 @@
### 3.5.2. Unicode
在很久以前, 世界比較簡單的, 起碼計算機就隻有一個ASCII字符集: 美信息交換標準代碼. ASCII, 更準確地説是美的ASCII, 使用 7bit 來表示 128 個字符: 包含英文字母的大小寫, 數字, 各種標點符號和設置控製符. 對於早期的計算機程序, 這些足夠了, 但是這也導致了世界上很多其他地區的用戶無法直接使用自己的書寫繫統. 隨着互聯網的發展, 混合多種語言的數據變了很常見. 如何有效處理這些包含了各種語言的豐富多樣的數據呢?
在很久以前, 世界比較簡單的, 起碼計算機就隻有一個ASCII字符集: 美信息交換標準代碼. ASCII, 更準確地説是美的ASCII, 使用 7bit 來表示 128 個字符: 包含英文字母的大小寫, 數字, 各種標點符號和設置控製符. 對於早期的計算機程序, 這些足夠了, 但是這也導致了世界上很多其他地區的用戶無法直接使用自己的書寫繫統. 隨着互聯網的發展, 混合多種語言的數據變了很常見. 如何有效處理這些包含了各種語言的豐富多樣的數據呢?
答案就是使用Unicode(unicode.org), 它收集了這個世界上所有的書寫繫統, 包括重音符號和其他變音符號, 製表符和迴車符, 還有很多神祕符號, 每個符號都分配一個Unicode碼點, Unicode碼點對應Go語言中的rune類型.

View File

@@ -1,5 +1,5 @@
# 第3章 基礎數據類型
雖然從底層而言,所有的數據都是比特,但計算機操作的是固定位數的數,如整數、浮點數、比特組、內存地址。將這些數,進一步組織在一起,可表達更多的對象,如數據包、像素點、詩歌,甚至任何對象.Go提供了豐富的數據組織形式,這依賴於Go內置的數據類型。這些內置的數據類型兼顧了硬件的特性和表達複雜數據結構的便捷性。
雖然從底層而言,所有的數據都是比特組成,但計算機一般操作的是固定大小的數,如整數、浮點數、比特組、內存地址等。進一步將這些數組織在一起,可表達更多的對象,如數據包、像素點、詩歌,甚至其他任何對象Go語言提供了豐富的數據組織形式這依賴於Go語言內置的數據類型。這些內置的數據類型,兼顧了硬件的特性和表達複雜數據結構的便捷性。
Go將數據類型分爲四類基礎類型、複合類型、引用類型和接口類型。本章介紹基礎類型包括數字字符串和布爾型。複合數據類型——數組§4.1和結構體§4.2——通過組合簡單類型表達更加複雜的數據結構。引用類型包括指針§2.3.2、切片§4.2)字典§4.3、函數§5、通道§8.雖然種類很多,但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。
Go語言將數據類型分爲四類:基礎類型、複合類型、引用類型和接口類型。本章介紹基礎類型,包括:數字字符串和布爾型。複合數據類型——數組§4.1和結構體§4.2)——通過組合簡單類型,表達更加複雜的數據結構。引用類型包括指針§2.3.2、切片§4.2)字典§4.3、函數§5、通道§8雖然數據種類很多但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用類型數據的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。