make loop

This commit is contained in:
chai2010
2015-12-18 14:49:31 +08:00
parent 9fde1ff772
commit f9ac065e47
106 changed files with 725 additions and 725 deletions

View File

@@ -1,8 +1,8 @@
## 6.5. 示例: Bit數組
Go語言的集合一般會用map[T]bool這種形式來表示T代表元素類型。集合用map類型來表示雖然非常靈活但我們可以以一種更好的形式來表示它。例如在數據流分析領域集合元素通常是一個非負整數集合會包含很多元素且集合會經常進行集、交集操作這種情況下bit數組會比map表現更加理想。(譯註:這再補充一個例子比如我們執行一個http下載任務把文件按照16kb一塊劃分爲很多塊需要有一個全變量來標識哪些塊下載完成了這種時候也需要用到bit數組)
Go語言的集合一般會用map[T]bool這種形式來表示T代表元素類型。集合用map類型來表示雖然非常靈活但我們可以以一種更好的形式來表示它。例如在數據流分析領域集合元素通常是一個非負整數集合會包含很多元素且集合會經常進行集、交集操作這種情況下bit數組會比map表現更加理想。(譯註:這再補充一個例子比如我們執行一個http下載任務把文件按照16kb一塊劃分爲很多塊需要有一個全變量來標識哪些塊下載完成了這種時候也需要用到bit數組)
一個bit數組通常會用一個無符號數或者稱之爲“字”的slice或者來表示每一個元素的每一位都表示集合的一個值。當集合的第i位被設置時我們纔這個集合包含元素i。下面的這個程序展示了一個簡單的bit數組類型且實現了三個函數來對這個bit數組來進行操作
一個bit數組通常會用一個無符號數或者稱之爲“字”的slice或者來表示每一個元素的每一位都表示集合的一個值。當集合的第i位被設置時我們纔這個集合包含元素i。下面的這個程序展示了一個簡單的bit數組類型且實現了三個函數來對這個bit數組來進行操作
```go
gopl.io/ch6/intset
@@ -39,9 +39,9 @@ func (s *IntSet) UnionWith(t *IntSet) {
}
```
因爲每一個字都有64個二進製位所以爲了定位x的bit位我們用了x/64的商作爲字的下標且用x%64得到的值作爲這個字內的bit的所在位置。UnionWith這個方法用到了bit位的“或”邏輯操作符號|來一次完成64個元素的或計算。(在練習6.5中我們還會程序用到這個64位字的例子。)
因爲每一個字都有64個二進製位所以爲了定位x的bit位我們用了x/64的商作爲字的下標且用x%64得到的值作爲這個字內的bit的所在位置。UnionWith這個方法用到了bit位的“或”邏輯操作符號|來一次完成64個元素的或計算。(在練習6.5中我們還會程序用到這個64位字的例子。)
當前這個實現還缺少了很多必要的特性我們把其中一些作爲練習題列在本小節之後。但是有一個方法如果缺失的話我們的bit數組可能會比較難混將IntSet作爲一個字符串來打印。這我們來實現它讓我們來給上面的例子添加一個String方法類似2.5節中做的那樣:
當前這個實現還缺少了很多必要的特性我們把其中一些作爲練習題列在本小節之後。但是有一個方法如果缺失的話我們的bit數組可能會比較難混將IntSet作爲一個字符串來打印。這我們來實現它讓我們來給上面的例子添加一個String方法類似2.5節中做的那樣:
```go
// String returns the set as a string of the form "{1 2 3}".
@@ -66,7 +66,7 @@ func (s *IntSet) String() string {
}
```
留意一下String方法是不是和3.5.4節中的intsToString方法很相似bytes.Buffer在String方法經常這麽用。當你爲一個雜的類型定義了一個String方法時fmt包就會特殊對待這種類型的值這樣可以讓這些類型在打印的時候看起來更加友好而不是直接打印其原始的值。fmt會直接調用用戶定義的String方法。這種機製依賴於接口和類型斷言在第7章中我們會詳細介紹。
留意一下String方法是不是和3.5.4節中的intsToString方法很相似bytes.Buffer在String方法經常這麽用。當你爲一個雜的類型定義了一個String方法時fmt包就會特殊對待這種類型的值這樣可以讓這些類型在打印的時候看起來更加友好而不是直接打印其原始的值。fmt會直接調用用戶定義的String方法。這種機製依賴於接口和類型斷言在第7章中我們會詳細介紹。
現在我們就可以在實戰中直接用上面定義好的IntSet了
```go
@@ -85,13 +85,13 @@ fmt.Println(x.String()) // "{1 9 42 144}"
fmt.Println(x.Has(9), x.Has(123)) // "true false"
```
要註意我們聲明的String和Has兩個方法都是以指類型*IntSet來作爲接收器的但實際上對於這兩個類型來,把接收器聲明爲指類型也沒什麽必要。不過另外兩個函數就不是這樣了因爲另外兩個函數操作的是s.words對象如果你不把接收器聲明爲指對象那麽實際操作的是拷貝對象而不是原來的那個對象。因此因爲我們的String方法定義在IntSet指所以當我們的變量是IntSet類型而不是IntSet指時,可能會有下面這樣讓人意外的情況:
要註意我們聲明的String和Has兩個方法都是以指類型*IntSet來作爲接收器的但實際上對於這兩個類型來,把接收器聲明爲指類型也沒什麽必要。不過另外兩個函數就不是這樣了因爲另外兩個函數操作的是s.words對象如果你不把接收器聲明爲指對象那麽實際操作的是拷貝對象而不是原來的那個對象。因此因爲我們的String方法定義在IntSet指所以當我們的變量是IntSet類型而不是IntSet指時,可能會有下面這樣讓人意外的情況:
```go
fmt.Println(&x) // "{1 9 42 144}"
fmt.Println(x.String()) // "{1 9 42 144}"
fmt.Println(x) // "{[4398046511618 0 65536]}"
```
在第一個Println中我們打印一個*IntSet的指,這個類型的指確實有自定義的String方法。第二Println我們直接調用了x變量的String()方法這種情況下編譯器會隱式地在x前插入&操作符這樣相當遠我們還是調用的IntSet指的String方法。在第三個Println中因爲IntSet類型沒有String方法所以Println方法會直接以原始的方式理解打印。所以在這種情況下&符號是不能忘的。在我們這種場景下你把String方法綁定到IntSet對象上而不是IntSet指上可能會更合適一些,不過這也需要具體問題具體分析。
在第一個Println中我們打印一個*IntSet的指,這個類型的指確實有自定義的String方法。第二Println我們直接調用了x變量的String()方法這種情況下編譯器會隱式地在x前插入&操作符這樣相當遠我們還是調用的IntSet指的String方法。在第三個Println中因爲IntSet類型沒有String方法所以Println方法會直接以原始的方式理解打印。所以在這種情況下&符號是不能忘的。在我們這種場景下你把String方法綁定到IntSet對象上而不是IntSet指上可能會更合適一些,不過這也需要具體問題具體分析。
練習6.1: 爲bit數組實現下面這些方法
```go
@@ -103,7 +103,7 @@ func (*IntSet) Copy() *IntSet // return a copy of the set
練習6.2: 定義一個變參方法(*IntSet).AddAll(...int)這個方法可以爲一組IntSet值求和比如s.AddAll(1,2,3)。
練習6.3: (*IntSet).UnionWith會用|操作符計算兩個集合的交集我們再爲IntSet實現另外的幾個函數IntersectWith(交集元素在A集合B集合均齣現),DifferenceWith(差集元素齣現在A集合未齣現在B集合),SymmetricDifference(差集元素齣現在A但沒有齣現在B或者齣現在B沒有齣現在A)。
練習6.4: 實現一個Elems方法返迴集合中的所有元素用於做一些range之類的遍操作。
練習6.3: (*IntSet).UnionWith會用|操作符計算兩個集合的交集我們再爲IntSet實現另外的幾個函數IntersectWith(交集元素在A集合B集合均齣現),DifferenceWith(差集元素齣現在A集合未齣現在B集合),SymmetricDifference(差集元素齣現在A但沒有齣現在B或者齣現在B沒有齣現在A)。
練習6.4: 實現一個Elems方法返迴集合中的所有元素用於做一些range之類的遍操作。
練習6.5: 我們這章定義的IntSet的每個字都是用的uint64類型但是64位的數值可能在32位的平上不高效。脩改程序使其使用uint類型這種類型對於32位平檯來說更合適。當然了,這我們可以不用簡單粗暴地除64可以定義一個常量來決定是用32還是64你可能會用到平的自動判斷的一個智能表達式32 << (^uint(0) >> 63)
練習6.5: 我們這章定義的IntSet的每個字都是用的uint64類型但是64位的數值可能在32位的平上不高效。脩改程序使其使用uint類型這種類型對於32位平颱來説更合適。當然了,這我們可以不用簡單粗暴地除64可以定義一個常量來決定是用32還是64你可能會用到平的自動判斷的一個智能表達式32 << (^uint(0) >> 63)