mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-16 11:23:40 +00:00
ch3-06 review
This commit is contained in:
parent
315fb47435
commit
f4f7797ee4
@ -1,9 +1,8 @@
|
|||||||
### 3.6.1. iota 常量生成器
|
### 3.6.1. iota 常量生成器
|
||||||
|
|
||||||
|
常量聲明可以使用iota常量生成器初始化,它用於生成一組以相似規則初始化的常量,但是不用每行都寫一遍初始化表達式。在一個const聲明語句中,在第一個聲明的常量所在的行,iota將會被置爲0,然後在每一個有常量聲明的行加一。
|
||||||
|
|
||||||
常量聲明可以使用 iota 常量生成器, 用於生成一組相似的常量值, 但是不用每行都寫一遍. 在一個 const 聲明語句中, 在開始一行 iota 將會被置爲0, 然後在每一個有常量聲明的行加一.
|
下面是來自time包的例子,它首先定義了一個Weekday命名類型,然後爲一週的每天定義了一個常量,從週日0開始。在其它編程語言中,這種類型一般被稱爲枚舉類型。
|
||||||
|
|
||||||
下面是來自 time 包的例子, 它首先定義了Weekday命名類型, 然後爲一週的每天定義一個常量, 從週日0開始. 這種類型一般被稱爲枚舉類型.
|
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
type Weekday int
|
type Weekday int
|
||||||
@ -19,9 +18,9 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
週一將對應0, 週一爲1, 如此等等.
|
週一將對應0,週一爲1,如此等等。
|
||||||
|
|
||||||
我們也可以在複雜的常量表達式中使用 iota, 下面是來自 net 包的例子, 用於給一個無符號整數的最低5bit的每個bit給定一個名字:
|
我們也可以在複雜的常量表達式中使用iota,下面是來自net包的例子,用於給一個無符號整數的最低5bit的每個bit指定一個名字:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
type Flags uint
|
type Flags uint
|
||||||
@ -35,7 +34,7 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
隨着 iota 的遞增, 每個常量對應表達式 1 << iota, 是連續的2的冪, 分别對應一個bit位置. 使用這些常量可以測試, 設置, 或清除對應的bit位的值:
|
隨着iota的遞增,每個常量對應表達式1 << iota,是連續的2的冪,分别對應一個bit位置。使用這些常量可以用於測試、設置或清除對應的bit位的值:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
gopl.io/ch3/netflag
|
gopl.io/ch3/netflag
|
||||||
@ -56,7 +55,7 @@ unc main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
下面是一個更複雜的例子, 每個常量都是1024的冪:
|
下面是一個更複雜的例子,每個常量都是1024的冪:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const (
|
const (
|
||||||
@ -72,8 +71,8 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
iota 機製也有其局限性. 例如, 它併不能用於産生1000的冪(KB,MB,等等), 因爲併沒有計算冪的運算符.
|
不過iota常量生成規則也有其局限性。例如,它併不能用於産生1000的冪(KB、MB等),因爲Go語言併沒有計算冪的運算符。
|
||||||
|
|
||||||
**練習3.13:** 編寫KB,MB的常量聲明, 然後擴展到YB.
|
**練習 3.13:** 編寫KB、MB的常量聲明,然後擴展到YB。
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
### 3.6.2. 無類型常量
|
### 3.6.2. 無類型常量
|
||||||
|
|
||||||
|
Go語言的常量有個不同尋常之處。雖然一個常量可以有任意有一個確定的基礎類型,例如int或float64,或者是類似time.Duration這樣命名的基礎類型,但是許多常量併沒有一個明確的基礎類型。編譯器爲這些沒有明確的基礎類型的數字常量提供比基礎類型更高精度的算術運算;你可以認爲至少有256bit的運算精度。這里有六種未明確類型的常量類型,分别是無類型的布爾型、無類型的整數、無類型的字符、無類型的浮點數、無類型的複數、無類型的字符串。
|
||||||
|
|
||||||
Go語言的常量有點不尋常. 雖然一個常量可以有任意有一個確定的基礎類型, 例如 int 或 float64, 或者是類似 time.Duration 這樣命名的基礎類型, 但是許多常量併沒有一個明確的基礎類型. 編譯期爲這些沒有明確的基礎類型的數字常量提供比基礎類型或機器更高精度的算術運算; 你可以認爲至少有256bit的運算精度. 這里有六種未明確類型的常量類型, 分别是 無類型的布爾型, 無類型的整數, 無類型的字符, 無類型的浮點數, 無類型的複數, 無類型的字符串.
|
通過延遲明確常量的具體類型,無類型的常量不僅可以提供更高的運算精度,而且可以直接用於更多的表達式而不需要顯式的類型轉換。例如,例子中的ZiB和YiB的值已經超出任何Go語言中整數類型能表達的范圍,但是它們依然是合法的常量,而且可以像下面常量表達式依然有效(譯註:YiB/ZiB是在編譯期計算出來的,併且結果常量是1024,是Go語言int變量能有效表示的):
|
||||||
|
|
||||||
通過延遲明確具體類型, 無類型的常量不僅可以提供更高的精度, 而且可以直接用於更多的表達式而不需要類型轉換. 例如 例子中的 ZiB 和 YiB 的值已經超出任何Go中整數類型能表達的范圍, 但是它們依然是合法的常量, 而且可以像下面表達式這樣使用:
|
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
fmt.Println(YiB/ZiB) // "1024"
|
fmt.Println(YiB/ZiB) // "1024"
|
||||||
```
|
```
|
||||||
|
|
||||||
另一個例子, math.Pi 無類型的浮點數常量, 可以直接用於任意需要浮點數或複數的地方:
|
另一個例子,math.Pi無類型的浮點數常量,可以直接用於任意需要浮點數或複數的地方:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
var x float32 = math.Pi
|
var x float32 = math.Pi
|
||||||
@ -17,7 +16,7 @@ var y float64 = math.Pi
|
|||||||
var z complex128 = math.Pi
|
var z complex128 = math.Pi
|
||||||
```
|
```
|
||||||
|
|
||||||
如果 math.Pi 被確定爲特定類型, 比如 float64, 那麽結果精度可能會不一樣, 同時對於需要float32或complex128類型值的地方會需要一個明確的類型轉換:
|
如果math.Pi被確定爲特定類型,比如float64,那麽結果精度可能會不一樣,同時對於需要float32或complex128類型值的地方則會強製需要一個明確的類型轉換:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const Pi64 float64 = math.Pi
|
const Pi64 float64 = math.Pi
|
||||||
@ -27,9 +26,9 @@ var y float64 = Pi64
|
|||||||
var z complex128 = complex128(Pi64)
|
var z complex128 = complex128(Pi64)
|
||||||
```
|
```
|
||||||
|
|
||||||
對於常量面值, 不同的寫法對應不同的類型. 例如 0, 0.0, 0i, 和 '\u0000' 雖然有着相同的常量值, 但是它們分别對應無類型的整數,無類型的浮點數,無類型的複數,和無類型的字符等不同的常量類型. 同樣, true 和 false 也是無類型的布爾類型, 字符串面值常量是無類型的字符串.
|
對於常量面值,不同的寫法可能會對應不同的類型。例如0、0.0、0i和'\u0000'雖然有着相同的常量值,但是它們分别對應無類型的整數、無類型的浮點數、無類型的複數和無類型的字符等不同的常量類型。同樣,true和false也是無類型的布爾類型,字符串面值常量是無類型的字符串類型。
|
||||||
|
|
||||||
前面説過除法運算符 / 根據操作數的類型生成對應類型的結果. 因此, 不同寫法的常量除法表達式可能對應不同的結果:
|
前面説過除法運算符/會根據操作數的類型生成對應類型的結果。因此,不同寫法的常量除法表達式可能對應不同的結果:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
var f float64 = 212
|
var f float64 = 212
|
||||||
@ -38,7 +37,7 @@ fmt.Println(5 / 9 * (f - 32)) // "0"; 5/9 is an untyped integer, 0
|
|||||||
fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 is an untyped float
|
fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 is an untyped float
|
||||||
```
|
```
|
||||||
|
|
||||||
隻有常量可以是無類型的. 當一個無類型的常量被賦值給一個變量, 就像上面的第一行語句, 或者是像其餘三個語句中右邊表達式中含有明確類型的值, 無類型的常量將會被隱式轉換爲對應的類型, 如果可能的話.
|
隻有常量可以是無類型的。當一個無類型的常量被賦值給一個變量的時候,就像上面的第一行語句,或者是像其餘三個語句中右邊表達式中含有明確類型的值,無類型的常量將會被隱式轉換爲對應的類型,如果轉換合法的話。
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
var f float64 = 3 + 0i // untyped complex -> float64
|
var f float64 = 3 + 0i // untyped complex -> float64
|
||||||
@ -56,7 +55,7 @@ f = float64(1e123)
|
|||||||
f = float64('a')
|
f = float64('a')
|
||||||
```
|
```
|
||||||
|
|
||||||
無論是隱式或顯式, 將一種類型轉換爲另一種類型要求目標可以表示原始值. 對於浮點數和複數, 可能會有舍入處理:
|
無論是隱式或顯式轉換,將一種類型轉換爲另一種類型都要求目標可以表示原始值。對於浮點數和複數,可能會有舍入處理:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const (
|
const (
|
||||||
@ -70,7 +69,7 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
對於一個沒有顯式類型的變量聲明(包括短變量聲明語法), 無類型的常量會被隱式轉爲默認的變量類型, 就像下面的例子:
|
對於一個沒有顯式類型的變量聲明語法(包括短變量聲明語法),無類型的常量會被隱式轉爲默認的變量類型,就像下面的例子:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
i := 0 // untyped integer; implicit int(0)
|
i := 0 // untyped integer; implicit int(0)
|
||||||
@ -79,16 +78,16 @@ f := 0.0 // untyped floating-point; implicit float64(0.0)
|
|||||||
c := 0i // untyped complex; implicit complex128(0i)
|
c := 0i // untyped complex; implicit complex128(0i)
|
||||||
```
|
```
|
||||||
|
|
||||||
註意默認類型是規則的: 無類型的整數常量默認轉換爲int, 對應不確定的尺寸, 但是浮點數好複數常量則默認轉換爲float64和complex128. Go語言本身併沒有不確定的尺寸的浮點數和複數類型, 因爲如何不知道浮點數類型的話很難寫出正確的數值算法.
|
註意默認類型是規則的:無類型的整數常量默認轉換爲int,對應不確定的內存大小,但是浮點數和複數常量則默認轉換爲float64和complex128。Go語言本身併沒有不確定內存大小的浮點數和複數類型,而且如果不知道浮點數類型的話將很難寫出正確的數值算法。
|
||||||
|
|
||||||
如果要給變量一個不同的類型, 我們必鬚顯式地將無類型的常量轉化爲所需的類型, 或給聲明的變量指定類型, 像下面例子這樣:
|
如果要給變量一個不同的類型,我們必鬚顯式地將無類型的常量轉化爲所需的類型,或給聲明的變量指定明確的類型,像下面例子這樣:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
var i = int8(0)
|
var i = int8(0)
|
||||||
var i int8 = 0
|
var i int8 = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
當嚐試將這些無類型的常量轉爲一個接口值時(見第7章), 這些默認類型將顯得尤爲重要, 因爲要靠它們明確接口對應的動態類型.
|
當嚐試將這些無類型的常量轉爲一個接口值時(見第7章),這些默認類型將顯得尤爲重要,因爲要靠它們明確接口對應的動態類型。
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
fmt.Printf("%T\n", 0) // "int"
|
fmt.Printf("%T\n", 0) // "int"
|
||||||
@ -97,7 +96,7 @@ fmt.Printf("%T\n", 0i) // "complex128"
|
|||||||
fmt.Printf("%T\n", '\000') // "int32" (rune)
|
fmt.Printf("%T\n", '\000') // "int32" (rune)
|
||||||
```
|
```
|
||||||
|
|
||||||
現在我們已經講述了Go語言中全部的基礎數據類型. 下一步將演示如何用基礎數據類型組合成數組或結構體等複雜數據類型, 然後構建用於解決實際編程問題的數據結構, 這將是第四章的討論主題.
|
現在我們已經講述了Go語言中全部的基礎數據類型。下一步將演示如何用基礎數據類型組合成數組或結構體等複雜數據類型,然後構建用於解決實際編程問題的數據結構,這將是第四章的討論主題。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
## 3.6. 常量
|
## 3.6. 常量
|
||||||
|
|
||||||
|
常量表達式的值在編譯期計算,而不是在運行期。每種常量的潛在類型都是基礎類型:boolean、string或數字。
|
||||||
|
|
||||||
常量表達式的值在編譯期計算, 而不是在運行期. 每種常量的潛在類型都是基礎類型: boolean, string, 或數字.
|
一個常量的聲明語句定義了常量的名字,和變量的聲明語法類似,常量的值不可脩改,這樣可以防止在運行期被意外或惡意的脩改。例如,常量比變量更適合用於表達像π之類的數學常數,因爲它們的值不會發生變化:
|
||||||
|
|
||||||
一個常量的聲明語句定義了常量的名字, 和變量的聲明語法類似, 常量的值不可脩改, 這樣可以防止在運行期被意外或惡意的脩改. 例如, 常量比變量更適合用於表達像 π 之類的數學常數, 因爲它們的值不會變化:
|
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const pi = 3.14159 // approximately; math.Pi is a better approximation
|
const pi = 3.14159 // approximately; math.Pi is a better approximation
|
||||||
```
|
```
|
||||||
|
|
||||||
和變量聲明一樣, 可以批量聲明多個常量; 這比較適合聲明一組相關的常量:
|
和變量聲明一樣,可以批量聲明多個常量;這比較適合聲明一組相關的常量:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const (
|
const (
|
||||||
@ -18,11 +17,11 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
許多常量的運算可以在編譯期完成, 這樣可以減少運行時的工作, 也方便其他編譯優化. 當操作數是常量時, 一些運行時的錯誤可以在編譯時發現, 例如整數除零, 字符串索引越界, 任何導致無效浮點數的操作等.
|
所有常量的運算都可以在編譯期完成,這樣可以減少運行時的工作,也方便其他編譯優化。當操作數是常量時,一些運行時的錯誤也可以在編譯時被發現,例如整數除零、字符串索引越界、任何導致無效浮點數的操作等。
|
||||||
|
|
||||||
常量間的所有算術運算, 邏輯運算和比較運算的結果也是常量, 對常量的類型轉換操作或以下函數調用都是返迴常量結果: len, cap, real, imag, complex, 和 unsafe.Sizeof(§13.1).
|
常量間的所有算術運算、邏輯運算和比較運算的結果也是常量,對常量的類型轉換操作或以下函數調用都是返迴常量結果:len、cap、real、imag、complex和unsafe.Sizeof(§13.1)。
|
||||||
|
|
||||||
因爲它們的值是在編譯期就確定的, 因此常量可以是構成類型的一部分, 例如用於指定數組類型的長度:
|
因爲它們的值是在編譯期就確定的,因此常量可以是構成類型的一部分,例如用於指定數組類型的長度:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const IPv4Len = 4
|
const IPv4Len = 4
|
||||||
@ -34,7 +33,7 @@ func parseIPv4(s string) IP {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
一個常量的聲明也可以包含一個類型和一個值, 但是如果沒有顯式指明類型, 那麽將從右邊的表達式推斷類型. 在下面的代碼中, time.Duration 是一個命名類型, 底層類型是 int64, time.Minute 是對應類型的常量. 下面聲明的兩個常量都是 time.Duration 類型, 可以通過 %T 參數打印類型信息:
|
一個常量的聲明也可以包含一個類型和一個值,但是如果沒有顯式指明類型,那麽將從右邊的表達式推斷類型。在下面的代碼中,time.Duration是一個命名類型,底層類型是int64,time.Minute是對應類型的常量。下面聲明的兩個常量都是time.Duration類型,可以通過%T參數打印類型信息:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const noDelay time.Duration = 0
|
const noDelay time.Duration = 0
|
||||||
@ -44,7 +43,7 @@ fmt.Printf("%T %[1]v\n", timeout) // "time.Duration 5m0s
|
|||||||
fmt.Printf("%T %[1]v\n", time.Minute) // "time.Duration 1m0s"
|
fmt.Printf("%T %[1]v\n", time.Minute) // "time.Duration 1m0s"
|
||||||
```
|
```
|
||||||
|
|
||||||
如果是批量聲明的常量, 除了第一個外其他常量的右邊的表發生可以省略, 如果省略則表示使用前面的表達式, 對應的常量類型也一樣. 例如:
|
如果是批量聲明的常量,除了第一個外其它的常量右邊的初始化表達式都可以省略,如果省略初始化表達式則表示使用前面常量的初始化表達式寫法,對應的常量類型也一樣的。例如:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
const (
|
const (
|
||||||
@ -57,7 +56,7 @@ const (
|
|||||||
fmt.Println(a, b, c, d) // "1 1 2 2"
|
fmt.Println(a, b, c, d) // "1 1 2 2"
|
||||||
```
|
```
|
||||||
|
|
||||||
如果隻是簡單地複製右邊的常量表達式, 併沒有太實用的價值. 但是它可以帶來其他的特性, 那就是 iota 常量生成器.
|
如果隻是簡單地複製右邊的常量表達式,其實併沒有太實用的價值。但是它可以帶來其它的特性,那就是iota常量生成器語法。
|
||||||
|
|
||||||
{% include "./ch3-06-1.md" %}
|
{% include "./ch3-06-1.md" %}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user