ch4-3: review

This commit is contained in:
chai2010 2016-01-07 13:25:12 +08:00
parent efcf1b4545
commit 91bf250bb1

View File

@ -97,7 +97,7 @@ for _, name := range names {
names := make([]string, 0, len(ages)) names := make([]string, 0, len(ages))
``` ```
在上面的第一個range循環中我們隻關心map中的key所以我們忽略了第二個循環變量。在第二個循環中我們隻關names中的名字所以我們使用“_”空白標識符來忽略第一個循環變量也就是迭代slice時的索引。 在上面的第一個range循環中我們隻關心map中的key所以我們忽略了第二個循環變量。在第二個循環中我們隻關names中的名字所以我們使用“_”空白標識符來忽略第一個循環變量也就是迭代slice時的索引。
map類型的零值是nil也就是沒有引用任何哈希表。 map類型的零值是nil也就是沒有引用任何哈希表。
@ -153,7 +153,7 @@ func equal(x, y map[string]int) bool {
equal(map[string]int{"A": 0}, map[string]int{"B": 42}) equal(map[string]int{"A": 0}, map[string]int{"B": 42})
``` ```
Go語言中併沒有提供一個set類型但是map中的key也是不相同的可以用map實現類似的功能。爲了説明這一點下面的dedup程序讀取多行輸入但是隻打印第一次出現的行。它是1.3節中出現的dup程序的變體。dedup程序通過map來表示所有的輸入行所對應的set集合以確保已經在集合存在的行不會被重複打印。 Go語言中併沒有提供一個set類型但是map中的key也是不相同的可以用map實現類似set的功能。爲了説明這一點下面的dedup程序讀取多行輸入但是隻打印第一次出現的行。它是1.3節中出現的dup程序的變體。dedup程序通過map來表示所有的輸入行所對應的set集合以確保已經在集合存在的行不會被重複打印。
```Go ```Go
gopl.io/ch4/dedup gopl.io/ch4/dedup
@ -178,7 +178,7 @@ func main() {
Go程序員將這種忽略value的map當作一個字符串集合併非所有`map[string]bool`類型value都是無關緊要的有一些則可能會同時包含tue和false的值。 Go程序員將這種忽略value的map當作一個字符串集合併非所有`map[string]bool`類型value都是無關緊要的有一些則可能會同時包含tue和false的值。
有時候我們需要一個map或set的key是slice類型但是map的key必鬚是可比較的但是slice併不滿足這個條件。不過我們可以通過兩個步驟繞過這個限製。第一步定義一個輔助函數k將slice轉爲map對應的string類型的key確保隻有x和y相等時k(x) == k(y)才成立。然後創建一個key爲string類型的map在每次對map操作時先用k輔助函數將slice轉化爲string類型。 有時候我們需要一個map或set的key是slice類型但是map的key必鬚是可比較的類型但是slice併不滿足這個條件。不過我們可以通過兩個步驟繞過這個限製。第一步定義一個輔助函數k將slice轉爲map對應的string類型的key確保隻有x和y相等時k(x) == k(y)才成立。然後創建一個key爲string類型的map在每次對map操作時先用k輔助函數將slice轉化爲string類型。
下面的例子演示了如何使用map來記録提交相同的字符串列表的次數。它使用了fmt.Sprintf函數將字符串列表轉換爲一個字符串以用於map的key通過%q參數忠實地記録每個字符串元素的信息 下面的例子演示了如何使用map來記録提交相同的字符串列表的次數。它使用了fmt.Sprintf函數將字符串列表轉換爲一個字符串以用於map的key通過%q參數忠實地記録每個字符串元素的信息
@ -191,9 +191,9 @@ func Add(list []string) { m[k(list)]++ }
func Count(list []string) int { return m[k(list)] } func Count(list []string) int { return m[k(list)] }
``` ```
使用同樣的技術可以處理任何不可比較的key類型而不僅僅是slice類型。對於想使用自定義key比較函數的時候也很有用例如在比較字符串的時候忽略大小寫。同時輔助函數k(x)也不一定是字符串類型,它可以返迴任何可比較的類型,例如整數、數組或結構體等。 使用同樣的技術可以處理任何不可比較的key類型而不僅僅是slice類型。這種技術對於想使用自定義key比較函數的時候也很有用例如在比較字符串的時候忽略大小寫。同時輔助函數k(x)也不一定是字符串類型,它可以返迴任何可比較的類型,例如整數、數組或結構體等。
這是map的另一個例子下面的程序用於統計輸入中每個Unicode碼點出現的次數。雖然Unicode全部碼點的數量鉅大但是出現在特點文檔中的字符併沒有多少使用map可以用比較自然的方式來跟蹤那些見過字符次數。 這是map的另一個例子下面的程序用於統計輸入中每個Unicode碼點出現的次數。雖然Unicode全部碼點的數量鉅大但是出現在特定文檔中的字符種類併沒有多少使用map可以用比較自然的方式來跟蹤那些出現過字符的次數。
```Go ```Go
gopl.io/ch4/charcount gopl.io/ch4/charcount
@ -248,11 +248,11 @@ func main() {
} }
``` ```
ReadRune方法執行UTF-8解碼併返迴三個值解碼的rune字符的值字符UTF-8編碼後的長度和一個錯誤值。我們可預期的錯誤值隻有對應文件結尾的io.EOF。如果輸入的是無效的UTF-8編碼的字符返迴的將是unicode.ReplacementChar無效字符併且編碼長度是1。 ReadRune方法執行UTF-8解碼併返迴三個值解碼的rune字符的值字符UTF-8編碼後的長度和一個錯誤值。我們可預期的錯誤值隻有對應文件結尾的io.EOF。如果輸入的是無效的UTF-8編碼的字符返迴的將是unicode.ReplacementChar表示無效字符併且編碼長度是1。
charcount程序同時打印不同UTF-8編碼長度的字符數目。對此map併不是一個合適的數據結構因爲UTF-8編碼的長度總是從1到utf8.UTFMax最大是4個字節使用數組將更有效。 charcount程序同時打印不同UTF-8編碼長度的字符數目。對此map併不是一個合適的數據結構因爲UTF-8編碼的長度總是從1到utf8.UTFMax最大是4個字節使用數組將更有效。
作爲一個實驗我們用charcount程序對本身的字符進行了統計。雖然大部分是英語但是也有一些非ASCII字符。下面是排名前10的非ASCII字符 作爲一個實驗我們用charcount程序對英文版原稿的字符進行了統計。雖然大部分是英語但是也有一些非ASCII字符。下面是排名前10的非ASCII字符
![](../images/ch4-xx-01.png) ![](../images/ch4-xx-01.png)
@ -287,7 +287,7 @@ func hasEdge(from, to string) bool {
} }
``` ```
其中addEdge函數惰性初始化map是一個慣用方式也就是説在每個值首次作爲key才初始化。addEdge函數顯示了如何讓map的零值也能正常工作卽使from到to的邊不存在graph[from][to]依然可以返迴一個有意義的結果。 其中addEdge函數惰性初始化map是一個慣用方式也就是説在每個值首次作爲key才初始化。addEdge函數顯示了如何讓map的零值也能正常工作卽使from到to的邊不存在graph[from][to]依然可以返迴一個有意義的結果。
**練習 4.8** 脩改charcount程序使用unicode.IsLetter等相關的函數統計字母、數字等Unicode中不同的字符類别。 **練習 4.8** 脩改charcount程序使用unicode.IsLetter等相關的函數統計字母、數字等Unicode中不同的字符類别。