mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-08-08 16:21:43 +00:00
ch2: fix code path
This commit is contained in:
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
一個Go語言編寫的程序對應一個或多個以.go爲文件後綴名的源文件中。每個源文件以包的聲明語句開始,説明該源文件是屬於哪個包。包聲明語句之後是import語句導入依賴的其它包,然後是包一級的類型、變量、常量、函數的聲明語句,包一級的各種類型的聲明語句的順序無關緊要(譯註:函數內部的名字則必須先聲明之後才能使用)。例如,下面的例子中聲明了一個常量、一個函數和兩個變量:
|
一個Go語言編寫的程序對應一個或多個以.go爲文件後綴名的源文件中。每個源文件以包的聲明語句開始,説明該源文件是屬於哪個包。包聲明語句之後是import語句導入依賴的其它包,然後是包一級的類型、變量、常量、函數的聲明語句,包一級的各種類型的聲明語句的順序無關緊要(譯註:函數內部的名字則必須先聲明之後才能使用)。例如,下面的例子中聲明了一個常量、一個函數和兩個變量:
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/boiling</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/boiling
|
|
||||||
// Boiling prints the boiling point of water.
|
// Boiling prints the boiling point of water.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -28,9 +28,8 @@ func main() {
|
|||||||
|
|
||||||
我們已經看到過很多函數聲明和函數調用的例子了,在第五章將深入討論函數的相關細節,這里隻簡單解釋下。下面的fToC函數封裝了溫度轉換的處理邏輯,這樣它隻需要被定義一次,就可以在多個地方多次被使用。在這個例子中,main函數就調用了兩次fToC函數,分别是使用在局部定義的兩個常量作爲調用函數的參數。
|
我們已經看到過很多函數聲明和函數調用的例子了,在第五章將深入討論函數的相關細節,這里隻簡單解釋下。下面的fToC函數封裝了溫度轉換的處理邏輯,這樣它隻需要被定義一次,就可以在多個地方多次被使用。在這個例子中,main函數就調用了兩次fToC函數,分别是使用在局部定義的兩個常量作爲調用函數的參數。
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/ftoc</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/ftoc
|
|
||||||
// Ftoc prints two Fahrenheit-to-Celsius conversions.
|
// Ftoc prints two Fahrenheit-to-Celsius conversions.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -46,4 +45,3 @@ func fToC(f float64) float64 {
|
|||||||
return (f - 32) * 5 / 9
|
return (f - 32) * 5 / 9
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -59,8 +59,8 @@ fmt.Println(incr(&v)) // "3" (and v is 3)
|
|||||||
|
|
||||||
指針是實現標準庫中flag包的關鍵技術,它使用命令行參數來設置對應變量的值,而這些對應命令行標誌參數的變量可能會零散分布在整個程序中。爲了説明這一點,在早些的echo版本中,就包含了兩個可選的命令行參數:`-n`用於忽略行尾的換行符,`-s sep`用於指定分隔字符(默認是空格)。下面這是第四個版本,對應包路徑爲gopl.io/ch2/echo4。
|
指針是實現標準庫中flag包的關鍵技術,它使用命令行參數來設置對應變量的值,而這些對應命令行標誌參數的變量可能會零散分布在整個程序中。爲了説明這一點,在早些的echo版本中,就包含了兩個可選的命令行參數:`-n`用於忽略行尾的換行符,`-s sep`用於指定分隔字符(默認是空格)。下面這是第四個版本,對應包路徑爲gopl.io/ch2/echo4。
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/echo4</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/echo4
|
|
||||||
// Echo4 prints its command-line arguments.
|
// Echo4 prints its command-line arguments.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@@ -102,4 +102,3 @@ Usage of ./echo4:
|
|||||||
-s string
|
-s string
|
||||||
separator (default " ")
|
separator (default " ")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -3,16 +3,16 @@
|
|||||||
使用賦值語句可以更新一個變量的值,最簡單的賦值語句是將要被賦值的變量放在=的左邊,新值的表達式放在=的右邊。
|
使用賦值語句可以更新一個變量的值,最簡單的賦值語句是將要被賦值的變量放在=的左邊,新值的表達式放在=的右邊。
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
x = 1 // 命令變量的賦值
|
x = 1 // 命名變量的賦值
|
||||||
*p = true // 通過指針間接賦值
|
*p = true // 通過指針間接賦值
|
||||||
person.name = "bob" // 結構體字段賦值
|
person.name = "bob" // 結構體字段賦值
|
||||||
count[x] = count[x] * scale // 數組、slice或map的元素賦值
|
count[x] = count[x] * scale // 數組、slice或map的元素賦值
|
||||||
```
|
```
|
||||||
|
|
||||||
特定的二元算術運算符和賦值語句的複合操作有一個簡潔形式,例如上面最後的語句可以重寫爲:
|
特定的二元算術運算符和賦值語句的複合操作有一個簡潔形式,例如上面最後的語句可以重寫爲:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
count[x] *= scale
|
count[x] *= scale
|
||||||
```
|
```
|
||||||
|
|
||||||
這樣可以省去對變量表達式的重複計算。
|
這樣可以省去對變量表達式的重複計算。
|
||||||
@@ -20,12 +20,11 @@ count[x] *= scale
|
|||||||
數值變量也可以支持`++`遞增和`--`遞減語句(譯註:自增和自減是語句,而不是表達式,因此`x = i++`之類的表達式是錯誤的):
|
數值變量也可以支持`++`遞增和`--`遞減語句(譯註:自增和自減是語句,而不是表達式,因此`x = i++`之類的表達式是錯誤的):
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
v := 1
|
v := 1
|
||||||
v++ // 等價方式 v = v + 1;v 變成 2
|
v++ // 等價方式 v = v + 1;v 變成 2
|
||||||
v-- // 等價方式 v = v - 1;v 變成 1
|
v-- // 等價方式 v = v - 1;v 變成 1
|
||||||
```
|
```
|
||||||
|
|
||||||
{% include "./ch2-04-1.md" %}
|
{% include "./ch2-04-1.md" %}
|
||||||
|
|
||||||
{% include "./ch2-04-2.md" %}
|
{% include "./ch2-04-2.md" %}
|
||||||
|
|
||||||
|
@@ -20,8 +20,8 @@ type 類型名字 底層類型
|
|||||||
|
|
||||||
爲了説明類型聲明,我們將不同溫度單位分别定義爲不同的類型:
|
爲了説明類型聲明,我們將不同溫度單位分别定義爲不同的類型:
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/tempconv0</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/tempconv0
|
|
||||||
// Package tempconv performs Celsius and Fahrenheit temperature computations.
|
// Package tempconv performs Celsius and Fahrenheit temperature computations.
|
||||||
package tempconv
|
package tempconv
|
||||||
|
|
||||||
@@ -90,5 +90,3 @@ fmt.Println(c) // "100°C"
|
|||||||
fmt.Printf("%g\n", c) // "100"; does not call String
|
fmt.Printf("%g\n", c) // "100"; does not call String
|
||||||
fmt.Println(float64(c)) // "100"; does not call String
|
fmt.Println(float64(c)) // "100"; does not call String
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@@ -6,32 +6,32 @@
|
|||||||
|
|
||||||
要使用gopl.io/ch2/tempconv包,需要先導入:
|
要使用gopl.io/ch2/tempconv包,需要先導入:
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/cf</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/cf
|
// Cf converts its numeric argument to Celsius and Fahrenheit.
|
||||||
// Cf converts its numeric argument to Celsius and Fahrenheit.
|
package main
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"gopl.io/ch2/tempconv"
|
"gopl.io/ch2/tempconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
for _, arg := range os.Args[1:] {
|
for _, arg := range os.Args[1:] {
|
||||||
t, err := strconv.ParseFloat(arg, 64)
|
t, err := strconv.ParseFloat(arg, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "cf: %v\n", err)
|
fmt.Fprintf(os.Stderr, "cf: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
f := tempconv.Fahrenheit(t)
|
f := tempconv.Fahrenheit(t)
|
||||||
c := tempconv.Celsius(t)
|
c := tempconv.Celsius(t)
|
||||||
fmt.Printf("%s = %s, %s = %s\n",
|
fmt.Printf("%s = %s, %s = %s\n",
|
||||||
f, tempconv.FToC(f), c, tempconv.CToF(c))
|
f, tempconv.FToC(f), c, tempconv.CToF(c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
導入語句將導入的包綁定到一個短小的名字,然後通過該短小的名字就可以引用包中導出的全部內容。上面的導入聲明將允許我們以tempconv.CToF的形式來訪問gopl.io/ch2/tempconv包中的內容。在默認情況下,導入的包綁定到tempconv名字(譯註:這包聲明語句指定的名字),但是我們也可以綁定到另一個名稱,以避免名字衝突(§10.4)。
|
導入語句將導入的包綁定到一個短小的名字,然後通過該短小的名字就可以引用包中導出的全部內容。上面的導入聲明將允許我們以tempconv.CToF的形式來訪問gopl.io/ch2/tempconv包中的內容。在默認情況下,導入的包綁定到tempconv名字(譯註:這包聲明語句指定的名字),但是我們也可以綁定到另一個名稱,以避免名字衝突(§10.4)。
|
||||||
@@ -39,13 +39,13 @@ func main() {
|
|||||||
cf程序將命令行輸入的一個溫度在Celsius和Fahrenheit溫度單位之間轉換:
|
cf程序將命令行輸入的一個溫度在Celsius和Fahrenheit溫度單位之間轉換:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go build gopl.io/ch2/cf
|
$ go build gopl.io/ch2/cf
|
||||||
$ ./cf 32
|
$ ./cf 32
|
||||||
32°F = 0°C, 32°C = 89.6°F
|
32°F = 0°C, 32°C = 89.6°F
|
||||||
$ ./cf 212
|
$ ./cf 212
|
||||||
212°F = 100°C, 212°C = 413.6°F
|
212°F = 100°C, 212°C = 413.6°F
|
||||||
$ ./cf -40
|
$ ./cf -40
|
||||||
-40°F = -40°C, -40°C = -40°F
|
-40°F = -40°C, -40°C = -40°F
|
||||||
```
|
```
|
||||||
|
|
||||||
如果導入了一個包,但是又沒有使用該包將被當作一個編譯錯誤處理。這種強製規則可以有效減少不必要的依賴,雖然在調試期間可能會讓人討厭,因爲刪除一個類似log.Print("got here!")的打印語句可能導致需要同時刪除log包導入聲明,否則,編譯器將會發出一個錯誤。在這種情況下,我們需要將不必要的導入刪除或註釋掉。
|
如果導入了一個包,但是又沒有使用該包將被當作一個編譯錯誤處理。這種強製規則可以有效減少不必要的依賴,雖然在調試期間可能會讓人討厭,因爲刪除一個類似log.Print("got here!")的打印語句可能導致需要同時刪除log包導入聲明,否則,編譯器將會發出一個錯誤。在這種情況下,我們需要將不必要的導入刪除或註釋掉。
|
||||||
@@ -53,6 +53,3 @@ $ ./cf -40
|
|||||||
不過有更好的解決方案,我們可以使用golang.org/x/tools/cmd/goimports導入工具,它可以根據需要自動添加或刪除導入的包;許多編輯器都可以集成goimports工具,然後在保存文件的時候自動運行。類似的還有gofmt工具,可以用來格式化Go源文件。
|
不過有更好的解決方案,我們可以使用golang.org/x/tools/cmd/goimports導入工具,它可以根據需要自動添加或刪除導入的包;許多編輯器都可以集成goimports工具,然後在保存文件的時候自動運行。類似的還有gofmt工具,可以用來格式化Go源文件。
|
||||||
|
|
||||||
**練習 2.2:** 寫一個通用的單位轉換程序,用類似cf程序的方式從命令行讀取參數,如果缺省的話則是從標準輸入讀取參數,然後做類似Celsius和Fahrenheit的單位轉換,長度單位可以對應英尺和米,重量單位可以對應磅和公斤等。
|
**練習 2.2:** 寫一個通用的單位轉換程序,用類似cf程序的方式從命令行讀取參數,如果缺省的話則是從標準輸入讀取參數,然後做類似Celsius和Fahrenheit的單位轉換,長度單位可以對應英尺和米,重量單位可以對應磅和公斤等。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -24,8 +24,8 @@ func init() { /* ... */ }
|
|||||||
|
|
||||||
下面的代碼定義了一個PopCount函數,用於返迴一個數字中含二進製1bit的個數。它使用init初始化函數來生成輔助表格pc,pc表格用於處理每個8bit寬度的數字含二進製的1bit的bit個數,這樣的話在處理64bit寬度的數字時就沒有必要循環64次,隻需要8次査表就可以了。(這併不是最快的統計1bit數目的算法,但是它可以方便演示init函數的用法,併且演示了如果預生成輔助表格,這是編程中常用的技術)。
|
下面的代碼定義了一個PopCount函數,用於返迴一個數字中含二進製1bit的個數。它使用init初始化函數來生成輔助表格pc,pc表格用於處理每個8bit寬度的數字含二進製的1bit的bit個數,這樣的話在處理64bit寬度的數字時就沒有必要循環64次,隻需要8次査表就可以了。(這併不是最快的統計1bit數目的算法,但是它可以方便演示init函數的用法,併且演示了如果預生成輔助表格,這是編程中常用的技術)。
|
||||||
|
|
||||||
|
<u><i>gopl.io/ch2/popcount</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/popcount
|
|
||||||
package popcount
|
package popcount
|
||||||
|
|
||||||
// pc[i] is the population count of i.
|
// pc[i] is the population count of i.
|
||||||
@@ -74,4 +74,3 @@ for i, _ := range pc {
|
|||||||
**練習 2.4:** 用移位算法重寫PopCount函數,每次測試最右邊的1bit,然後統計總數。比較和査表算法的性能差異。
|
**練習 2.4:** 用移位算法重寫PopCount函數,每次測試最右邊的1bit,然後統計總數。比較和査表算法的性能差異。
|
||||||
|
|
||||||
**練習 2.5:** 表達式`x&(x-1)`用於將x的最低的一個非零的bit位清零。使用這個算法重寫PopCount函數,然後比較性能。
|
**練習 2.5:** 表達式`x&(x-1)`用於將x的最低的一個非零的bit位清零。使用這個算法重寫PopCount函數,然後比較性能。
|
||||||
|
|
||||||
|
@@ -12,8 +12,8 @@ Go語言中的包和其他語言的庫或模塊的概念類似,目的都是爲
|
|||||||
|
|
||||||
我們把變量的聲明、對應的常量,還有方法都放到tempconv.go源文件中:
|
我們把變量的聲明、對應的常量,還有方法都放到tempconv.go源文件中:
|
||||||
|
|
||||||
|
<u></i>gopl.io/ch2/tempconv</i></u>
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch2/tempconv
|
|
||||||
// Package tempconv performs Celsius and Fahrenheit conversions.
|
// Package tempconv performs Celsius and Fahrenheit conversions.
|
||||||
package tempconv
|
package tempconv
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user