mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-17 19:24:19 +08:00
make loop
This commit is contained in:
@@ -8,7 +8,7 @@ Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int1
|
||||
|
||||
字符rune類型是和int32等價的類型, 通常用於表示一個Unicode碼點. 這兩個名稱可以互換使用. 同樣byte也是uint8類型的等價類型, byte類型用於強調數值是一個原始的數據而不是一個小的整數.
|
||||
|
||||
最好, 還有一個無符號的整數類型 uintptr, 沒有指定具體的bit大小但是足以容納指針. uintptr 類型隻有在底層編程是纔需要, 特别是Go語言和C函數庫或操作繫統相交互的地方. 我們將在第十三章的 unsafe 包相關部分看到類似的例子.
|
||||
最好, 還有一個無符號的整數類型 uintptr, 沒有指定具體的bit大小但是足以容納指針. uintptr 類型隻有在底層編程是才需要, 特别是Go語言和C函數庫或操作繫統相交互的地方. 我們將在第十三章的 unsafe 包相關部分看到類似的例子.
|
||||
|
||||
不管它們的大小, int, uint, 和 uintptr 是不同類型大小的兄弟類型. 其中 int 和 int32 也是不同的類型, 卽使int的大小也是32bit, 在需要將int當作int32類型的地方需要一個顯式的類型轉換, 反之亦然.
|
||||
|
||||
@@ -31,7 +31,7 @@ Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int1
|
||||
整數的算術運算符 +, -, *, 和 / 可以適用與整數, 浮點數和複數, 但是取模運算符 % 僅用於整數. 不同編程語言間, % 取模運算的行爲併不相同. 在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
|
||||
@@ -102,13 +102,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.
|
||||
|
||||
左移運算用零填充右邊空缺的bit位, 無符號數的右移運算也是用0填充左邊空缺的bit位, 但是有符號數的右移運算會用符號位的值填充左邊空缺的bit位. 因爲這個原因, 最好用無符號運算, 這樣你可以將整數完全當作一個bit位模式處理.
|
||||
|
||||
盡管Go提供了無符號數和運算, 卽使數值本身不可能齣現負數我們還是傾向於使用有符號的int類型, 就是數組的長度那樣, 雖然使用 uint 似乎是一個更合理的選擇. 事實上, 內置的 len 函數返迴一個有符號的int, 我們可以像下面這個逆序循環那樣處理.
|
||||
盡管Go提供了無符號數和運算, 卽使數值本身不可能出現負數我們還是傾向於使用有符號的int類型, 就是數組的長度那樣, 雖然使用 uint 似乎是一個更合理的選擇. 事實上, 內置的 len 函數返迴一個有符號的int, 我們可以像下面這個逆序循環那樣處理.
|
||||
|
||||
```Go
|
||||
medals := []string{"gold", "silver", "bronze"}
|
||||
@@ -119,7 +119,7 @@ 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), 也就是試圖訪問一個切片范圍以外的元素.
|
||||
|
||||
齣於這個原因, 無符號數往往隻有在位運算或其它特殊的運算常見纔會使用, 就像 bit 集合, 分形二進製文件格式, 或者是哈希和加密操作等. 它們通常併不用於僅僅是表達非負數量的場合.
|
||||
出於這個原因, 無符號數往往隻有在位運算或其它特殊的運算常見才會使用, 就像 bit 集合, 分形二進製文件格式, 或者是哈希和加密操作等. 它們通常併不用於僅僅是表達非負數量的場合.
|
||||
|
||||
一般來説, 需要一個顯式的轉換將一個值從一種類型轉化位另一種類型, 併且算術和邏輯運算的二元操作中必鬚是相同的類型. 雖然這偶爾會導致很長的表達式, 但是它消除了所有的類型相關的問題, 也使得程序容易理解.
|
||||
|
||||
@@ -162,7 +162,7 @@ i := int(f) // 結果依賴於具體實現
|
||||
|
||||
任何大小的整數字面值都可以用以0開始的八進製格式書寫, 例如 0666, 或用以0x或0X開頭的十六進製格式書寫, 例如 0xdeadbeef. 十六進製數字可以用大寫或小寫字母. 如今八進製數據通常用於POSIX操作繫統上的文件訪問權限標誌, 十六進製數字則更強調數字值的bit位模式.
|
||||
|
||||
當使用 fmt 包打印一個數值時, 我們可以用 %d, %o, 或 %x 控製輸齣的進製格式, 就像下面的例子:
|
||||
當使用 fmt 包打印一個數值時, 我們可以用 %d, %o, 或 %x 控製輸出的進製格式, 就像下面的例子:
|
||||
|
||||
```Go
|
||||
o := 0666
|
||||
@@ -173,7 +173,7 @@ 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碼點對應的字符, 馬上將會看到例子.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ x = 6 e^x = 403.429
|
||||
x = 7 e^x = 1096.633
|
||||
```
|
||||
|
||||
math 包中除了提供大量常用的數學函數外, 還提供了IEEE754標準中特殊數值的創建和測試: 正無窮大和負無窮大, 分别用於表示太大溢齣的數字和除零的結果; 還有 NaN 非數, 一般用於表示無效的除法操作結果 0/0 或 Sqrt(-1).
|
||||
math 包中除了提供大量常用的數學函數外, 還提供了IEEE754標準中特殊數值的創建和測試: 正無窮大和負無窮大, 分别用於表示太大溢出的數字和除零的結果; 還有 NaN 非數, 一般用於表示無效的除法操作結果 0/0 或 Sqrt(-1).
|
||||
|
||||
```Go
|
||||
var z float64
|
||||
@@ -72,7 +72,7 @@ func compute() (value float64, ok bool) {
|
||||
}
|
||||
```
|
||||
|
||||
接下來的程序演示了浮點計算圖形. 它是帶有兩個參數的 z = f(x, y) 函數的三維形式, 使用了可縮放矢量圖形(SVG)格式輸齣, 一個用於矢量線繪製的XML標準. 圖3.1顯示了 sin(r)/r 函數的輸齣圖形, 其中 r 是 sqrt(x*x+y*y).
|
||||
接下來的程序演示了浮點計算圖形. 它是帶有兩個參數的 z = f(x, y) 函數的三維形式, 使用了可縮放矢量圖形(SVG)格式輸出, 一個用於矢量線繪製的XML標準. 圖3.1顯示了 sin(r)/r 函數的輸出圖形, 其中 r 是 sqrt(x*x+y*y).
|
||||
|
||||

|
||||
|
||||
@@ -147,11 +147,11 @@ func f(x, y float64) float64 {
|
||||
|
||||
(x,y,z) 投影到二維的畵布中. 畵布中從遠處到右邊的點對應較大的x值和較大的y值. 併且畵布中x和y值越大, 則對應的z值越小. x和y的垂直和水平縮放繫數來自30度角的正絃和餘絃值. z的縮放繫數0.4, 是一個任意選擇的參數.
|
||||
|
||||
對於二維網格中的每一個單位, main函數計算單元的四個頂點在畵布中對應多邊形ABCD的頂點, 其中B對應(i,j)頂點位置, A, C, 和 D是相鄰的頂點, 然後輸齣SVG的繪製指令.
|
||||
對於二維網格中的每一個單位, main函數計算單元的四個頂點在畵布中對應多邊形ABCD的頂點, 其中B對應(i,j)頂點位置, A, C, 和 D是相鄰的頂點, 然後輸出SVG的繪製指令.
|
||||
|
||||
**練習3.1:** 如果 f 函數返迴的是無限製的 float64 值, 那麽SVG文件可能輸齣無效的<polygon>多邊形元素(雖然許多SVG渲染器會妥善處理這類問題). 脩改程序跳過無效的多邊形.
|
||||
**練習3.1:** 如果 f 函數返迴的是無限製的 float64 值, 那麽SVG文件可能輸出無效的<polygon>多邊形元素(雖然許多SVG渲染器會妥善處理這類問題). 脩改程序跳過無效的多邊形.
|
||||
|
||||
**練習3.2:** 試驗math包中其他函數的渲染圖形. 你是否能輸齣一個egg box, moguls, 或 a saddle 圖案?
|
||||
**練習3.2:** 試驗math包中其他函數的渲染圖形. 你是否能輸出一個egg box, moguls, 或 a saddle 圖案?
|
||||
|
||||
**練習3.3:**根據高度給每個多邊形上色, 那樣峯值部將是紅色(#ff0000), 谷部將是藍色(#0000ff).
|
||||
|
||||
@@ -161,6 +161,6 @@ func f(x, y float64) float64 {
|
||||
w.Header().Set("Content-Type", "image/svg+xml")
|
||||
```
|
||||
|
||||
(這一步在Lissajous例子中不是必鬚的, 因爲服務器使用標準的PNG圖像格式, 可以根據前面的512個字節自動輸齣對應的頭部.) 允許客戶端通過HTTP請求參數設置高度, 寬度, 和顔色等參數.
|
||||
(這一步在Lissajous例子中不是必鬚的, 因爲服務器使用標準的PNG圖像格式, 可以根據前面的512個字節自動輸出對應的頭部.) 允許客戶端通過HTTP請求參數設置高度, 寬度, 和顔色等參數.
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ x := 1 + 2i
|
||||
y := 3 + 4i
|
||||
```
|
||||
|
||||
複數也可以用 == 和 != 進行相等比較. 隻有兩個複數的實部和虛部都相等的時候它們纔是相等的.
|
||||
複數也可以用 == 和 != 進行相等比較. 隻有兩個複數的實部和虛部都相等的時候它們才是相等的.
|
||||
|
||||
math/cmplx 包提供了複數處理的許多函數, 例如求複數的平方根函數和求冪函數.
|
||||
|
||||
@@ -83,7 +83,7 @@ func mandelbrot(z complex128) color.Color {
|
||||
}
|
||||
```
|
||||
|
||||
遍歷1024x1024圖像每個點的兩個嵌套的循環對應 -2 到 +2 區間的複數平面. 程序反複測試每個點對應複數值平方值加一個增量值對應的點是否超齣半徑爲2的圓. 如果超過了, 通過根據逃逸的迭代次數對應的灰度顔色來代替. 如果不是, 該點屬於Mandelbrot集合, 使用黑色顔色標記. 最終程序將生成的PNG格式分形圖像圖像輸齣到標準輸齣, 如圖3.3所示.
|
||||
遍歷1024x1024圖像每個點的兩個嵌套的循環對應 -2 到 +2 區間的複數平面. 程序反複測試每個點對應複數值平方值加一個增量值對應的點是否超出半徑爲2的圓. 如果超過了, 通過根據逃逸的迭代次數對應的灰度顔色來代替. 如果不是, 該點屬於Mandelbrot集合, 使用黑色顔色標記. 最終程序將生成的PNG格式分形圖像圖像輸出到標準輸出, 如圖3.3所示.
|
||||
|
||||
**練習3.5:** 實現一個綵色的Mandelbrot圖像, 使用 image.NewRGBA 創建圖像, 使用 color.RGBA 或 color.YCbCr 生成顔色.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ UTF8是一個將Unicode碼點編碼爲字節序列的變長編碼. UTF8編碼由
|
||||
|
||||
變長的編碼無法直接通過索引來訪問第n個字符, 但是UTF8穫得了很多額外的優點. 首先UTF8編碼比較緊湊, 兼容ASCII, 併且可以自動同步: 它可以通過向前迴朔最多2個字節就能確定當前字符編碼的開始字節的位置. 它也是一個前綴編碼, 所以當從左向右解碼時不會有任何歧義也併不需要向前査看. 沒有任何字符的編碼是其它字符編碼的子串, 或是其它編碼序列的字串, 因此蒐索一個字符時隻要蒐索它的字節編碼序列卽可, 不用擔心前後的上下文會對蒐索結果産生榦擾. 同時UTF8編碼的順序和Unicode碼點的順序一致, 因此可以直接排序UTF8編碼序列. 同業也沒有嵌入的NUL(0)字節, 可以很好地兼容那些使用NUL作爲字符串結尾的編程語言.
|
||||
|
||||
Go的源文件采用UTF8編碼, 併且Go處理UTF8編碼的文本也很齣色. unicode 包提供了諸多處理 rune 字符相關功能的函數函數(區分字母和數組, 或者是字母的大寫和小寫轉換等), unicode/utf8 包了提供了rune 字符序列的UTF8編碼和解碼的功能.
|
||||
Go的源文件采用UTF8編碼, 併且Go處理UTF8編碼的文本也很出色. unicode 包提供了諸多處理 rune 字符相關功能的函數函數(區分字母和數組, 或者是字母的大寫和小寫轉換等), unicode/utf8 包了提供了rune 字符序列的UTF8編碼和解碼的功能.
|
||||
|
||||
有很多Unicode字符很難直接從鍵盤輸入, 併且很多字符有着相似的結構; 有一些甚至是不可見的字符. Go字符串面值中的Unicode轉義字符讓我們可以通過Unicode碼點輸入特殊的字符. 有兩種形式, \uhhhh 對應16bit的碼點值, \Uhhhhhhhh 對應32bit的碼點值, 其中h是一個十六進製數字; 一般很少需要使用32bit的形式. 每一個對應碼點的UTF8編碼. 例如: 下面的字母串面值都表示相同的值:
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ func main() {
|
||||
|
||||
當向 bytes.Buffer 添加任意字符的UTF8編碼, 最好使用 bytes.Buffer 的 WriteRune 方法, 但是 WriteByte 方法對於寫入類似 '[' 和 ']' 等 ASCII 字符則更有效.
|
||||
|
||||
bytes.Buffer 類型有着諸多實用的功能, 我們在第七章討論接口時層涉及到, 我們將看看如何將它用作一個I/O 的輸入和輸齣對象, 例如 Fprintf 的 io.Writer 輸齣, 或作爲輸入源 io.Reader.
|
||||
bytes.Buffer 類型有着諸多實用的功能, 我們在第七章討論接口時層涉及到, 我們將看看如何將它用作一個I/O 的輸入和輸出對象, 例如 Fprintf 的 io.Writer 輸出, 或作爲輸入源 io.Reader.
|
||||
|
||||
**練習3.10:** 編寫一個非遞歸版本的comma函數, 使用 bytes.Buffer 代替字符串鏈接操作.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ fmt.Println(len(s)) // "12"
|
||||
fmt.Println(s[0], s[7]) // "104 119" ('h' and 'w')
|
||||
```
|
||||
|
||||
如果視圖訪問超齣字符串范圍的字節將會導致panic異常:
|
||||
如果視圖訪問超出字符串范圍的字節將會導致panic異常:
|
||||
|
||||
```Go
|
||||
c := s[len(s)] // panic: index out of range
|
||||
@@ -24,7 +24,7 @@ c := s[len(s)] // panic: index out of range
|
||||
fmt.Println(s[0:5]) // "hello"
|
||||
```
|
||||
|
||||
同樣, 如果索引超齣字符串范圍或者j小於i的話將導致panic異常.
|
||||
同樣, 如果索引超出字符串范圍或者j小於i的話將導致panic異常.
|
||||
|
||||
不管i還是j都可能被忽略, 當它們被忽略時將采用0作爲開始位置, 采用 len(s) 作爲接受的位置.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
Go語言的常量有點不尋常. 雖然一個常量可以有任意有一個確定的基礎類型, 例如 int 或 float64, 或者是類似 time.Duration 這樣命名的基礎類型, 但是許多常量併沒有一個明確的基礎類型. 編譯期爲這些沒有明確的基礎類型的數字常量提供比基礎類型或機器更高精度的算術運算; 你可以認爲至少有256bit的運算精度. 這里有六種未明確類型的常量類型, 分别是 無類型的布爾型, 無類型的整數, 無類型的字符, 無類型的浮點數, 無類型的複數, 無類型的字符串.
|
||||
|
||||
通過延遲明確具體類型, 無類型的常量不僅可以提供更高的精度, 而且可以直接用於更多的表達式而不需要類型轉換. 例如 例子中的 ZiB 和 YiB 的值已經超齣任何Go中整數類型能表達的范圍, 但是它們依然是合法的常量, 而且可以像下面表達式這樣使用:
|
||||
通過延遲明確具體類型, 無類型的常量不僅可以提供更高的精度, 而且可以直接用於更多的表達式而不需要類型轉換. 例如 例子中的 ZiB 和 YiB 的值已經超出任何Go中整數類型能表達的范圍, 但是它們依然是合法的常量, 而且可以像下面表達式這樣使用:
|
||||
|
||||
```Go
|
||||
fmt.Println(YiB/ZiB) // "1024"
|
||||
@@ -79,7 +79,7 @@ f := 0.0 // untyped floating-point; implicit float64(0.0)
|
||||
c := 0i // untyped complex; implicit complex128(0i)
|
||||
```
|
||||
|
||||
註意默認類型是規則的: 無類型的整數常量默認轉換爲int, 對應不確定的尺寸, 但是浮點數好複數常量則默認轉換爲float64和complex128. Go語言本身併沒有不確定的尺寸的浮點數和複數類型, 因爲如何不知道浮點數類型的話很難寫齣正確的數值算法.
|
||||
註意默認類型是規則的: 無類型的整數常量默認轉換爲int, 對應不確定的尺寸, 但是浮點數好複數常量則默認轉換爲float64和complex128. Go語言本身併沒有不確定的尺寸的浮點數和複數類型, 因爲如何不知道浮點數類型的話很難寫出正確的數值算法.
|
||||
|
||||
如果要給變量一個不同的類型, 我們必鬚顯式地將無類型的常量轉化爲所需的類型, 或給聲明的變量指定類型, 像下面例子這樣:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user