回到简体

This commit is contained in:
chai2010
2016-02-15 11:06:34 +08:00
parent 9e878f9944
commit 2b37b23285
177 changed files with 2354 additions and 2354 deletions

View File

@@ -1,20 +1,20 @@
## 3.1. 整型
Go言的數值類型包括幾種不同大小的整形、浮點數和複數。每種數值類型都定了對應的大小范和是否支持正負符號。讓我們先從整形數類型開始介
Go言的数值类型包括几种不同大小的整形、浮点数和复数。每种数值类型都定了对应的大小范和是否支持正负符号。让我们先从整形数类型开始介
Go言同提供了有符號和無符號類型的整數運算。里有int8、int16、int32和int64四截然不同大小的有符整形數類型,分别對應8、16、32、64bit大小的有符整形數,與此對應的是uint8、uint16、uint32和uint64四種無符號整形數類型。
Go言同提供了有符号和无符号类型的整数运算。里有int8、int16、int32和int64四截然不同大小的有符整形数类型,分别对应8、16、32、64bit大小的有符整形数,与此对应的是uint8、uint16、uint32和uint64四种无符号整形数类型。
這里還有兩種一般對應特定CPU平台器字大小的有符號和無符號整數int和uint其中int是用最泛的數值類型。這兩種類型都有同的大小32或64bit但是我不能此做任何的假;因不同的編譯器卽使在相同的硬件平台上可能生不同的大小。
这里还有两种一般对应特定CPU平台器字大小的有符号和无符号整数int和uint其中int是用最广泛的数值类型。这两种类型都有同的大小32或64bit但是我不能此做任何的假;因不同的编译器即使在相同的硬件平台上可能生不同的大小。
Unicode字符rune型是和int32等價的類型,通常用表示一Unicode碼點。這兩個名稱可以互使用。同byte也是uint8型的等價類byte型一般用於強調數值是一原始的數據而不是一小的整
Unicode字符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型的地方需要一個顯式的類型轉換操作,反之亦然。
不管它的具大小int、uint和uintptr是不同型的兄弟型。其中int和int32也是不同的型,使int的大小也是32bit在需要int作int32型的地方需要一个显式的类型转换操作,反之亦然。
其中有符號整數采用2的補碼形式表示也就是最高bit位用作表示符位,一n-bit的有符號數的值域是$$-2^{n-1}$$到$$2^{n-1}-1$$。無符號整數的所有bit位都用表示非負數值域是0到$$2^n-1$$。例如int8型整的值域是-128到127而uint8型整的值域是0到255。
其中有符号整数采用2的补码形式表示也就是最高bit位用作表示符位,一n-bit的有符号数的值域是$$-2^{n-1}$$到$$2^{n-1}-1$$。无符号整数的所有bit位都用表示非负数值域是0到$$2^n-1$$。例如int8型整的值域是-128到127而uint8型整的值域是0到255。
下面是Go言中關於算術運算、邏輯運算和比較運算的二元算符,它按照先級遞減的順序的排列:
下面是Go言中关于算术运算、逻辑运算和比较运算的二元算符,它按照先级递减的顺序的排列:
```
* / % << >> & &^
@@ -24,13 +24,13 @@ Unicode字符rune類型是和int32等價的類型通常用於表示一個Unic
||
```
二元算符有五種優先級。在同一個優先級,使用左優先結合規則,但是使用括可以明確優先順序,使用括也可以用於提陞優先級,例如`mask & (1 << 28)`
二元算符有五种优先级。在同一个优先级,使用左优先结合规则,但是使用括可以明确优先顺序,使用括也可以用于提升优先级,例如`mask & (1 << 28)`
對於上表中前行的算符,例如+算符有一個與賦值相合的對應運算符+=,可以用於簡化賦值語句。
对于上表中前行的算符,例如+算符有一个与赋值相合的对应运算符+=,可以用于简化赋值语句。
術運算符+、-、`*``/`可以適用與於整數、浮點數和複數,但是取模算符%僅用於整數間的運算。對於不同編程語言,%取模算的行可能不相同。在Go言中,%取模算符的符和被取模的符號總是一致的,因此`-5%3``-5%-3`果都是-2。除法算符`/`的行爲則依賴於操作是否爲全爲整數,比如`5.0/4.0`果是1.25但是5/4的果是1爲整數除法向着0方向截斷餘數
术运算符+、-、`*``/`可以适用与于整数、浮点数和复数,但是取模算符%仅用于整数间的运算。对于不同编程语言,%取模算的行可能不相同。在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
@@ -40,7 +40,7 @@ var i int8 = 127
fmt.Println(i, i+1, i*i) // "127 -128 1"
```
兩個相同的整數類型可以使用下面的二元比較運算符行比;比較表達式的果是布爾類型。
两个相同的整数类型可以使用下面的二元比较运算符行比;比较表达式的果是布尔类型。
```
== equal to
@@ -51,31 +51,31 @@ fmt.Println(i, i+1, i*i) // "127 -128 1"
>= greater than or equal to
```
上,布型、數字類型和字符串等基本型都是可比的,也就是説兩個相同型的值可以用==和!=行比。此外,整、浮點數和字符串可以根據比較結果排序。多其它型的值可能是不可比的,因此也就可能是不可排序的。對於我們遇到的每種類型,我需要保證規則的一致性。
上,布型、数字类型和字符串等基本型都是可比的,也就是说两个相同型的值可以用==和!=行比。此外,整、浮点数和字符串可以根据比较结果排序。多其它型的值可能是不可比的,因此也就可能是不可排序的。对于我们遇到的每种类型,我需要保证规则的一致性。
里是一元的加法和減法運算符:
里是一元的加法和减法运算符:
```
+ 一元加法 (效果)
- 負數
+ 一元加法 (效果)
- 负数
```
對於整數+x是0+x的簡寫-x是0-x的簡寫;對於浮點數和複數+x就是x-x是x 的負數
对于整数+x是0+x的简写-x是0-x的简写;对于浮点数和复数+x就是x-x是x 的负数
Go語言還提供了以下的bit位操作算符前面4操作算符併不區分是有符號還是無符號數
Go语言还提供了以下的bit位操作算符前面4操作算符并不区分是有符号还是无符号数
```
& 位算 AND
| 位算 OR
^ 位算 XOR
& 位算 AND
| 位算 OR
^ 位算 XOR
&^ 位清空 (AND NOT)
<< 左移
>> 右移
```
位操作算符`^`二元算符是按位XOR用作一元算符表示按位取反;也就是,它返迴一個每個bit位都取反的。位操作算符`&^`按位置零AND NOT`z = x &^ y`果z的bit位0如果對應y中bit位1的,否則對應的bit位等x相的bit位的值。
位操作算符`^`二元算符是按位XOR用作一元算符表示按位取反;也就是,它返回一个每个bit位都取反的。位操作算符`&^`按位置零AND NOT`z = x &^ y`果z的bit位0如果对应y中bit位1的,否则对应的bit位等x相的bit位的值。
下面的代演示了如何使用位操作解uint8型值的8個獨立的bit位。它使用了Printf函的%b參數打印二進製格式的字;其中%08b中08表示打印至少8字符度,不足的前部分用0填充。
下面的代演示了如何使用位操作解uint8型值的8个独立的bit位。它使用了Printf函的%b参数打印二进制格式的字;其中%08b中08表示打印至少8字符度,不足的前部分用0填充。
```Go
var x uint8 = 1<<1 | 1<<5
@@ -99,13 +99,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$$。
`x<<n``x>>n`移位算中,定了移位操作bit部分必须是无符号数被操作的x可以是有符号或无符号数。算上,一`x<<n`左移算等价于乘以$$2^n$$,一`x>>n`右移算等价于除以$$2^n$$。
左移算用零填充右空缺的bit位無符號數的右移算也是用0填充左空缺的bit位但是有符號數的右移運算會用符位的值填充左空缺的bit位。因爲這個原因,最好用無符號運算,這樣你可以將整數完全作一bit位模式理。
左移算用零填充右空缺的bit位无符号数的右移算也是用0填充左空缺的bit位但是有符号数的右移运算会用符位的值填充左空缺的bit位。因为这个原因,最好用无符号运算,这样你可以将整数完全作一bit位模式理。
管Go言提供了無符號數和運算,卽使數值本身不可能出現負數我們還是傾向於使用有符的int型,就像數組的長度那樣,雖然使用uint無符號類型似乎是一更合理的選擇。事上,置的len函數返迴一個有符的int可以像下面例子那樣處理逆序循
管Go言提供了无符号数和运算,即使数值本身不可能出现负数我们还是倾向于使用有符的int型,就像数组的长度那样,虽然使用uint无符号类型似乎是一更合理的选择。事上,置的len函数返回一个有符的int可以像下面例子那样处理逆序循
```Go
medals := []string{"gold", "silver", "bronze"}
@@ -114,13 +114,13 @@ 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),也就是試圖訪問一個slice范以外的元素。
另一个选择对于上面的例子来说将是灾难性的。如果len函数返回一个无符号数,那i也将是无符号的uint型,然后条`i >= 0`则永远为真。在三次迭代之,也就是`i == 0`i--语句将不会产生-1而是成一uint型的最大值(可能是$$2^64-1$$),然medals[i]表达式将发生运行时panic§5.9),也就是试图访问一个slice范以外的元素。
於這個原因,無符號數往往有在位算或其它特殊的運算場景才使用就像bit集合、分析二進製文件格式或者是哈希和加密操作等。它通常不用於僅僅是表達非負數量的合。
于这个原因,无符号数往往有在位算或其它特殊的运算场景才使用就像bit集合、分析二进制文件格式或者是哈希和加密操作等。它通常不用于仅仅是表达非负数量的合。
一般來説,需要一個顯式的轉換將一個值從一種類型轉化位另一種類型,且算術和邏輯運算的二元操作中必是相同的型。雖然這偶爾會導致需要很的表式,但是它消除了所有和型相關的問題,而且也使得程序容易理解。
一般来说,需要一个显式的转换将一个值从一种类型转化位另一种类型,且算术和逻辑运算的二元操作中必是相同的型。虽然这偶尔会导致需要很的表式,但是它消除了所有和型相关的问题,而且也使得程序容易理解。
在很多景,遇到似下面的代通用的錯誤
在很多景,遇到似下面的代通用的错误
```Go
var apples int32 = 1
@@ -128,19 +128,19 @@ var oranges int16 = 2
var compote int = apples + oranges // compile error
```
當嚐試編譯這三個語句時,將産生一個錯誤信息:
当尝试编译这三个语句时,将产生一个错误信息:
```
invalid operation: apples + oranges (mismatched types int32 and int16)
```
這種類型不匹配的問題可以有幾種不同的方法脩複,最常方法是將它們都顯式轉型爲一個常見類型:
这种类型不匹配的问题可以有几种不同的方法修复,最常方法是将它们都显式转型为一个常见类型:
```Go
var compote = int(apples) + int(oranges)
```
如2.5所述,對於每種類型T如果轉換允許的話類型轉換操作T(x)將x轉換爲T類型。多整形數之間的相互轉換併不會改變數值;它們隻是告訴編譯器如何解釋這個值。但是對於將一個大尺寸的整數類型轉爲一個小尺寸的整數類型,或者是將一個浮點數轉爲整數,可能會改變數值或失精度:
如2.5所述,对于每种类型T如果转换允许的话类型转换操作T(x)将x转换为T类型。多整形数之间的相互转换并不会改变数值;它们只是告诉编译器如何解释这个值。但是对于将一个大尺寸的整数类型转为一个小尺寸的整数类型,或者是将一个浮点数转为整数,可能会改变数值或失精度:
```Go
f := 3.141 // a float64
@@ -150,16 +150,16 @@ f = 1.99
fmt.Println(int(f)) // "1"
```
點數到整數的轉換將丟失任何小部分,然後向數軸零方向截。你應該避免可能超出目標類型表示范圍的數值類型轉換,因爲截斷的行可能依賴於具體的實現
点数到整数的转换将丢失任何小部分,然后向数轴零方向截。你应该避免可能超出目标类型表示范围的数值类型转换,因为截断的行可能依赖于具体的实现
```Go
f := 1e100 // a float64
i := int(f) // 果依賴於具體實現
i := int(f) // 果依赖于具体实现
```
任何大小的整字面值都可以用以0始的八進製格式書寫例如0666或用以0x或0X開頭的十六進製格式書寫例如0xdeadbeef。十六進製數字可以用大或小字母。如今八進製數據通常用POSIX操作繫統上的文件訪問權限標誌,十六進製數字則更強調數字值的bit位模式。
任何大小的整字面值都可以用以0始的八进制格式书写例如0666或用以0x或0X开头的十六进制格式书写例如0xdeadbeef。十六进制数字可以用大或小字母。如今八进制数据通常用POSIX操作系统上的文件访问权限标志,十六进制数字则更强调数字值的bit位模式。
使用fmt包打印一個數值時,我可以用%d、%o或%x參數控製輸出的進製格式,就像下面的例子:
使用fmt包打印一个数值时,我可以用%d、%o或%x参数控制输出的进制格式,就像下面的例子:
```Go
o := 0666
@@ -170,11 +170,11 @@ 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碼點對應的字符,馬上將會看到這樣的例子。
字符面值通过一对单引号直接包含对应字符。最简单的例子是ASCII中似'a'法的字符面值,但是我也可以通过转义的数值来表示任意的Unicode码点对应的字符,马上将会看到这样的例子。
字符使用`%c`參數打印,或者是用`%q`參數打印帶單引號的字符:
字符使用`%c`参数打印,或者是用`%q`参数打印带单引号的字符:
```Go
ascii := 'a'

View File

@@ -1,30 +1,30 @@
## 3.2. 浮點數
## 3.2. 浮点数
Go言提供了兩種精度的浮點數float32和float64。它的算術規范由IEEE754浮點數国際標準定義,該浮點數規范被所有代的CPU支持。
Go言提供了两种精度的浮点数float32和float64。它的算术规范由IEEE754浮点数国际标准定义,该浮点数规范被所有代的CPU支持。
些浮點數類型的取值范可以很微小到很大。浮點數的范圍極限值可以在math包找到。常量math.MaxFloat32表示float32能表示的最大值,大是 3.4e38對應的math.MaxFloat64常量大是1.8e308。它分别能表示的最小值近似1.4e-45和4.9e-324。
些浮点数类型的取值范可以很微小到很大。浮点数的范围极限值可以在math包找到。常量math.MaxFloat32表示float32能表示的最大值,大是 3.4e38对应的math.MaxFloat64常量大是1.8e308。它分别能表示的最小值近似1.4e-45和4.9e-324。
float32型的浮點數可以提供大約6個十進製數的精度而float64可以提供15個十進製數的精度;通常應該優先使用float64型,因float32型的纍計計算誤差很容易散,且float32能精表示的正整數併不是很大(譯註:因float32的有效bit位有23其它的bit位用於指數和符號;當整數大於23bit能表的范圍時float32的表示將出現誤差):
float32型的浮点数可以提供大约6个十进制数的精度而float64可以提供15个十进制数的精度;通常应该优先使用float64型,因float32型的累计计算误差很容易散,且float32能精表示的正整数并不是很大(译注:因float32的有效bit位有23其它的bit位用于指数和符号;当整数大于23bit能表的范围时float32的表示将出现误差):
```Go
var f float32 = 16777216 // 1 << 24
fmt.Println(f == f+1) // "true"!
```
點數的字面值可以直接寫小數部分,像這樣
点数的字面值可以直接写小数部分,像这样
```Go
const e = 2.71828 // (approximately)
```
數點前面或面的字都可能被省略(例如.707或1.)。很小或很大的最好用科學計數法書寫,通e或E指定指部分:
数点前面或面的字都可能被省略(例如.707或1.)。很小或很大的最好用科学计数法书写,通e或E指定指部分:
```Go
const Avogadro = 6.02214129e23 // 阿伏伽德羅常數
const Planck = 6.62606957e-34 // 普朗剋常數
const Avogadro = 6.02214129e23 // 阿伏伽德罗常数
const Planck = 6.62606957e-34 // 普朗克常数
```
用Printf函的%g參數打印浮點數,將采用更緊湊的表示形式打印,提供足的精度,但是對應表格的數據,使用%e帶指數)或%f的形式打印可能更合。所有的這三個打印形式都可以指定打印的度和控打印精度。
用Printf函的%g参数打印浮点数,将采用更紧凑的表示形式打印,提供足的精度,但是对应表格的数据,使用%e带指数)或%f的形式打印可能更合。所有的这三个打印形式都可以指定打印的度和控打印精度。
```Go
for x := 0; x < 8; x++ {
@@ -32,7 +32,7 @@ for x := 0; x < 8; x++ {
}
```
上面代打印e的,打印精度是小數點後三個小數精度和8字符度:
上面代打印e的,打印精度是小数点后三个小数精度和8字符度:
```
x = 0 e^x = 1.000
@@ -45,21 +45,21 @@ 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
fmt.Println(z, -z, 1/z, -1/z, z/z) // "0 -0 +Inf -Inf NaN"
```
math.IsNaN用於測試一個數是否是非NaNmath.NaN則返迴非數對應的值。然可以用math.NaN表示一非法的果,但是測試一個結果是否是非NaN是充滿風險的,因NaN和任何都是不相等的(譯註:在浮點數NaN、正無窮大和負無窮大都不是唯一的,每都有非常多的bit模式表示
math.IsNaN用于测试一个数是否是非NaNmath.NaN则返回非数对应的值。然可以用math.NaN表示一非法的果,但是测试一个结果是否是非NaN是充满风险的,因NaN和任何都是不相等的(译注:在浮点数NaN、正无穷大和负无穷大都不是唯一的,每都有非常多的bit模式表示
```Go
nan := math.NaN()
fmt.Println(nan == nan, nan < nan, nan > nan) // "false false false"
```
如果一個函數返迴的浮點數結果可能失,最好的做法是用單獨的標誌報告失,像這樣
如果一个函数返回的浮点数结果可能失,最好的做法是用单独的标志报告失,像这样
```Go
func compute() (value float64, ok bool) {
@@ -71,7 +71,7 @@ func compute() (value float64, ok bool) {
}
```
接下的程序演示了通過浮點計算生成的形。它是帶有兩個參數的z = f(x, y)函的三形式,使用了可放矢量SVG格式SVG是一個用於矢量線繪製的XML標準。圖3.1示了sin(r)/r函數的輸出圖其中r是sqrt(x*x+y*y)。
接下的程序演示了通过浮点计算生成的形。它是带有两个参数的z = f(x, y)函的三形式,使用了可放矢量SVG格式SVG是一个用于矢量线绘制的XML标准。图3.1示了sin(r)/r函数的输出图其中r是sqrt(x*x+y*y)。
![](../images/ch3-01.png)
@@ -133,30 +133,30 @@ func f(x, y float64) float64 {
}
```
意的是corner函數返迴了兩個結果,分别對應每個網格頂點的坐標參數
意的是corner函数返回了两个结果,分别对应每个网格顶点的坐标参数
要解釋這個程序是如何工作的需要一些基本的幾何學知識,但是我可以跳過幾何學原理,因程序的重是演示浮點數運算。程序的本是三不同的坐標繫中映射關繫,如3.2所示。第一是100x100的二維網格,對應整數整數坐標(i,j)從遠處的(0, 0)位置始。我們從遠處向前面繪製,因此遠處先繪製的多形有可能被前面後繪製的多形覆
要解释这个程序是如何工作的需要一些基本的几何学知识,但是我可以跳过几何学原理,因程序的重是演示浮点数运算。程序的本是三不同的坐标系中映射关系,如3.2所示。第一是100x100的二维网格,对应整数整数坐标(i,j)从远处的(0, 0)位置始。我们从远处向前面绘制,因此远处先绘制的多形有可能被前面后绘制的多形覆
第二個坐標繫是一個三維的網格浮點坐標(x,y,z)其中x和y是i和j的性函,通平移轉換位網格單元的中心,然用xyrange繫數縮放。高度z是函f(x,y)的值。
第二个坐标系是一个三维的网格浮点坐标(x,y,z)其中x和y是i和j的线性函,通平移转换位网格单元的中心,然用xyrange系数缩放。高度z是函f(x,y)的值。
第三個坐標繫是一個二維的畵布,起(0,0)在左上角。布中的坐用(sx, sy)表示。我使用等角投影將三維點
第三个坐标系是一个二维的画布,起(0,0)在左上角。布中的坐用(sx, sy)表示。我使用等角投影将三维点
![](../images/ch3-02.png)
(x,y,z)投影到二維的畵布中。布中從遠處到右邊的點對應較大的x值和大的y值。併且畵布中x和y值越大則對應的z值越小。x和y的垂直和水平縮放繫數來自30度角的正絃和餘絃值。z的縮放繫數0.4,是一任意選擇的參數
(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)。
**练习 3.3**高度给每个多边形上色,那样峰值部将是红色(#ff0000),谷部将是蓝色(#0000ff)。
**練習 3.4** 考1.7Lissajous例子的函數,構造一web服器,用於計算函數麴面然後返迴SVG數據給客戶端。服器必須設置Content-Type部:
**练习 3.4** 考1.7Lissajous例子的函数,构造一web服器,用于计算函数曲面然后返回SVG数据给客户端。服器必须设置Content-Type部:
```Go
w.Header().Set("Content-Type", "image/svg+xml")
```
一步在Lissajous例子中不是必的,因爲服務器使用標準的PNG像格式,可以根前面的512個字節自動輸出對應的頭部。)允許客戶端通HTTP請求參數設置高度、度和色等參數
一步在Lissajous例子中不是必的,因为服务器使用标准的PNG像格式,可以根前面的512个字节自动输出对应的头部。)允许客户端通HTTP请求参数设置高度、度和色等参数

View File

@@ -1,6 +1,6 @@
## 3.3. 複數
## 3.3. 复数
Go言提供了兩種精度的複數類complex64和complex128分别對應float32和float64兩種浮點數精度。置的complex函數用於構建複數,內建的real和imag函分别返迴複數的實部和部:
Go言提供了两种精度的复数类complex64和complex128分别对应float32和float64两种浮点数精度。置的complex函数用于构建复数,内建的real和imag函分别返回复数的实部和部:
```Go
var x complex128 = complex(1, 2) // 1+2i
@@ -10,28 +10,28 @@ fmt.Println(real(x*y)) // "-5"
fmt.Println(imag(x*y)) // "10"
```
如果一個浮點數面值或一個十進製整數面值面跟着一i例如3.141592i或2i將構成一個複數的虛部,複數的實部是0
如果一个浮点数面值或一个十进制整数面值面跟着一i例如3.141592i或2i将构成一个复数的虚部,复数的实部是0
```Go
fmt.Println(1i * 1i) // "(-1+0i)", i^2 = -1
```
在常量算術規則下,一個複數常量可以加到另一普通值常量(整或浮點數、實部或部),我可以用自然的方式書寫複數就像1+2i或之等價的寫法2i+1。上面x和y的聲明語句還可以化:
在常量算术规则下,一个复数常量可以加到另一普通值常量(整或浮点数、实部或部),我可以用自然的方式书写复数就像1+2i或之等价的写法2i+1。上面x和y的声明语句还可以化:
```Go
x := 1 + 2i
y := 3 + 4i
```
複數也可以用==和!=行相等比較。隻有兩個複數的實部和部都相等的候它才是相等的(譯註:浮點數的相等比是危的,需要特别小心理精度問題)。
复数也可以用==和!=行相等比较。只有两个复数的实部和部都相等的候它才是相等的(译注:浮点数的相等比是危的,需要特别小心理精度问题)。
math/cmplx包提供了複數處理的多函,例如求複數的平方根函和求冪函數
math/cmplx包提供了复数处理的多函,例如求复数的平方根函和求幂函数
```Go
fmt.Println(cmplx.Sqrt(-1)) // "(0+1i)"
```
下面的程序使用complex128複數算法生成一Mandelbrot像。
下面的程序使用complex128复数算法生成一Mandelbrot像。
<u><i>gopl.io/ch3/mandelbrot</i></u>
```Go
@@ -81,16 +81,16 @@ func mandelbrot(z complex128) color.Color {
}
```
於遍歷1024x1024像每個點的兩個嵌套的循環對應-2到+2區間的複數平面。程序反複測試每個點對應複數值平方值加一增量值對應的點是否超出半徑爲2的。如果超了,通過根據預設置的逃逸迭代次數對應的灰度顔色來代替。如果不是,那麽該點屬於Mandelbrot集合使用黑色顔色標記。最程序生成的PNG格式分形圖像圖像輸出到標準輸出,如3.3所示。
于遍历1024x1024像每个点的两个嵌套的循环对应-2到+2区间的复数平面。程序反复测试每个点对应复数值平方值加一增量值对应的点是否超出半径为2的。如果超了,通过根据预设置的逃逸迭代次数对应的灰度颜色来代替。如果不是,那么该点属于Mandelbrot集合使用黑色颜色标记。最程序生成的PNG格式分形图像图像输出到标准输出,如3.3所示。
![](../images/ch3-03.png)
**練習 3.5** 實現一個綵色的Mandelbrot使用image.NewRGBA創建圖使用color.RGBA或color.YCbCr生成色。
**练习 3.5** 实现一个彩色的Mandelbrot使用image.NewRGBA创建图使用color.RGBA或color.YCbCr生成色。
**練習 3.6** 陞采樣技術可以降低每像素對計算顔色值和平均值的影響。簡單的方法是將每個像素分層四個子像素,實現它。
**练习 3.6** 升采样技术可以降低每像素对计算颜色值和平均值的影响。简单的方法是将每个像素分层四个子像素,实现它。
**練習 3.7** 另一生成分形像的方式是使用牛頓法來求解一個複數方程,例如$$z^4-1=0$$。每個起點到四根的迭代次數對應陰影的灰度。方程根對應的點用顔色表示。
**练习 3.7** 另一生成分形像的方式是使用牛顿法来求解一个复数方程,例如$$z^4-1=0$$。每个起点到四根的迭代次数对应阴影的灰度。方程根对应的点用颜色表示。
**練習 3.8**提高精度生成更多别的分形。使用四不同精度型的數字實現相同的分形complex64、complex128、big.Float和big.Rat。後面兩種類型在math/big包明。Float是有指定限精度的浮點數Rat是效精度的有理。)它們間的性能和存使用比如何?渲染圖可見時縮放的别是多少?
**练习 3.8**提高精度生成更多别的分形。使用四不同精度型的数字实现相同的分形complex64、complex128、big.Float和big.Rat。后面两种类型在math/big包明。Float是有指定限精度的浮点数Rat是效精度的有理。)它们间的性能和存使用比如何?渲染图可见时缩放的别是多少?
**練習 3.9** 編寫一個web服器,用於給客戶端生成分形的像。行客端用HTTP參數參數指定x,y和zoom參數
**练习 3.9** 编写一个web服器,用于给客户端生成分形的像。行客端用HTTP参数参数指定x,y和zoom参数

View File

@@ -1,16 +1,16 @@
## 3.4. 布
## 3.4. 布
個布爾類型的值隻有兩種true和false。if和for句的件部分都是布爾類型的值,且==和<等比操作也會産生布型的值一元操作符`!`對應邏輯非操作因此`!true`的值`false`嗦的法是`(!true==false)==true`然表方式不一過我們一般采用簡潔的布爾表達就像用x表示`x==true`
个布尔类型的值只有两种true和false。if和for句的件部分都是布尔类型的值,且==和<等比操作也会产生布型的值一元操作符`!`对应逻辑非操作因此`!true`的值`false`嗦的法是`(!true==false)==true`然表方式不一过我们一般采用简洁的布尔表达就像用x表示`x==true`
值可以和&&AND||OR操作符且可能有短路行如果算符左值已可以定整個布爾表達式的值麽運算符右的值不在被求值因此下面的表達式總是安全的
值可以和&&AND||OR操作符且可能有短路行如果算符左值已可以定整个布尔表达式的值么运算符右的值不在被求值因此下面的表达式总是安全的
```Go
s != "" && s[0] == 'x'
```
其中s[0]操作如果應用於空字符串將會導致panic
其中s[0]操作如果应用于空字符串将会导致panic
`&&`優先級`||``&&`對應邏輯乘法`||`對應邏輯加法乘法比加法優先級要高下面形式的布爾表達式是不需要加小括弧的
`&&`优先级`||``&&`对应逻辑乘法`||`对应逻辑加法乘法比加法优先级要高下面形式的布尔表达式是不需要加小括弧的
```Go
if 'a' <= c && c <= 'z' ||
@@ -20,7 +20,7 @@ if 'a' <= c && c <= 'z' ||
}
```
爾值併不會隱式轉換爲數字值0或1反之亦然使用一個顯式的if語句輔助轉換
尔值并不会隐式转换为数字值0或1反之亦然使用一个显式的if语句辅助转换
```Go
i := 0
@@ -29,7 +29,7 @@ if b {
}
```
如果需要常做似的轉換, 成一個函數會更方便:
如果需要常做似的转换, 成一个函数会更方便:
```Go
// btoi returns 1 if b is true and 0 if false.
@@ -41,7 +41,7 @@ func btoi(b bool) int {
}
```
字到布型的逆轉換則非常簡單, 過爲了保持對稱, 也可以包裝一個函數:
字到布型的逆转换则非常简单, 过为了保持对称, 也可以包装一个函数:
```Go
// itob reports whether i is non-zero.

View File

@@ -1,6 +1,6 @@
### 3.5.1. 字符串面值
字符串值也可以用字符串面值方式編寫,隻要將一繫列字序列包含在雙引號卽可:
字符串值也可以用字符串面值方式编写,只要将一系列字序列包含在双引号即可:
```
"Hello, 世界"
@@ -8,28 +8,28 @@
![](../images/ch3-04.png)
Go言源文件是用UTF8編碼,併且Go言的文本字符串也以UTF8編碼的方式理,因此我可以Unicode碼點也寫到字符串面值中。
Go言源文件是用UTF8编码,并且Go言的文本字符串也以UTF8编码的方式理,因此我可以Unicode码点也写到字符串面值中。
在一個雙引號包含的字符串面值中,可以用以反斜`\`開頭的轉義序列插入任意的數據。下面的行、迴車和製表符等是常的ASCII控製代碼的轉義方式:
在一个双引号包含的字符串面值中,可以用以反斜`\`开头的转义序列插入任意的数据。下面的行、回车和制表符等是常的ASCII控制代码的转义方式:
```
\a 響鈴
\a 响铃
\b 退格
\f 換頁
\n
\r 迴車
\t 表符
\v 垂直表符
\' 單引號 (用在 '\'' 形式的rune符面值中)
\" 雙引號 (用在 "..." 形式的字符串面值中)
\\ 反斜
\f 换页
\n
\r 回车
\t 表符
\v 垂直表符
\' 单引号 (用在 '\'' 形式的rune符面值中)
\" 双引号 (用在 "..." 形式的字符串面值中)
\\ 反斜
```
可以通十六進製或八進製轉義在字符串面值包含任意的字。一十六進製的轉義形式是\xhh其中兩個h表示十六進製數字(大或小都可以)。一個八進製轉義形式是\ooo包含三個八進製的o0到7但是不能超`\377`譯註:對應一個字節的范,十進製爲255。每一個單一的字節表達一個特定的值。稍後我們將看到如何將一個Unicode碼點寫到字符串面值中。
可以通十六进制或八进制转义在字符串面值包含任意的字。一十六进制的转义形式是\xhh其中两个h表示十六进制数字(大或小都可以)。一个八进制转义形式是\ooo包含三个八进制的o0到7但是不能超`\377`译注:对应一个字节的范,十进制为255。每一个单一的字节表达一个特定的值。稍后我们将看到如何将一个Unicode码点写到字符串面值中。
原生的字符串面值形式是`...`,使用反引```代替雙引號。在原生的字符串面值中,沒有轉義操作;全部的容都是字面的意思,包含退格和行,因此一程序中的原生字符串面值可能跨越多行(譯註:在原生字符串面值部是法直接```字符的,可以用八進製或十六進製轉義或+"```"接字符串常量完成)。唯一的特殊理是會刪除迴車以保在所有平台上的值都是一的,包括那些把迴車也放入文本文件的繫統(譯註Windows繫統會把迴車和換行一起放入文本文件中)。
原生的字符串面值形式是`...`,使用反引```代替双引号。在原生的字符串面值中,没有转义操作;全部的容都是字面的意思,包含退格和行,因此一程序中的原生字符串面值可能跨越多行(译注:在原生字符串面值部是法直接```字符的,可以用八进制或十六进制转义或+"```"接字符串常量完成)。唯一的特殊理是会删除回车以保在所有平台上的值都是一的,包括那些把回车也放入文本文件的系统(译注Windows系统会把回车和换行一起放入文本文件中)。
原生字符串面值用於編寫正則表達式會很方便,因爲正則表達式往往包含很多反斜。原生字符串面值同時被廣泛應用於HTML模、JSON面值、命令行提示信息以及那些需要展到多行的景。
原生字符串面值用于编写正则表达式会很方便,因为正则表达式往往包含很多反斜。原生字符串面值同时被广泛应用于HTML模、JSON面值、命令行提示信息以及那些需要展到多行的景。
```Go
const GoUsage = `Go is a tool for managing Go source code.

View File

@@ -1,12 +1,12 @@
### 3.5.2. Unicode
在很久以前,世界是比較簡單的,起碼計算機世界就有一ASCII字符集美国信息交換標準代碼。ASCII準確地説是美国的ASCII使用7bit表示128字符:包含英文字母的大小寫、數字、各種標點符號和設置控符。對於早期的計算機程序來説,這些就足了,但是這也導致了世界上很多其他地的用戶無法直接使用自己的符號繫統。隨着互聯網的發展,混合多種語言的數據變得很常見(譯註:比如本身的英文原文或中文翻都包含了ASCII、中文、日文等多種語言字符)。如何有效處理這些包含了各種語言的富多的文本數據呢?
在很久以前,世界是比较简单的,起码计算机世界就有一ASCII字符集美国信息交换标准代码。ASCII准确地说是美国的ASCII使用7bit表示128字符:包含英文字母的大小写、数字、各种标点符号和设置控符。对于早期的计算机程序来说,这些就足了,但是这也导致了世界上很多其他地的用户无法直接使用自己的符号系统。随着互联网的发展,混合多种语言的数据变得很常见(译注:比如本身的英文原文或中文翻都包含了ASCII、中文、日文等多种语言字符)。如何有效处理这些包含了各种语言的富多的文本数据呢?
答案就是使用Unicode http://unicode.org ),它收集了這個世界上所有的符號繫統,包括重音符和其它音符號,製表符和迴車符,有很多神的符,每個符號都分配一唯一的Unicode碼點Unicode碼點對應Go言中的rune整數類型(譯註rune是int32等價類型)。
答案就是使用Unicode http://unicode.org ),它收集了这个世界上所有的符号系统,包括重音符和其它音符号,制表符和回车符,有很多神的符,每个符号都分配一唯一的Unicode码点Unicode码点对应Go言中的rune整数类型(译注rune是int32等价类型)。
在第八版本的Unicode標準收集了超120,000字符,涵蓋超過100多種語言。些在計算機程序和數據中是如何體現的呢?通用的表示一Unicode碼點的數據類型是int32也就是Go言中rune對應的類型;它的同義詞rune符文正是這個意思。
在第八版本的Unicode标准收集了超120,000字符,涵盖超过100多种语言。些在计算机程序和数据中是如何体现的呢?通用的表示一Unicode码点的数据类型是int32也就是Go言中rune对应的类型;它的同义词rune符文正是这个意思。
可以將一個符文序列表示爲一個int32序列。這種編碼方式叫UTF-32或UCS-4Unicode碼點都使用同的大小32bit表示。這種方式比較簡單統一,但是它會浪費很多存儲空間,因爲大數據計算機可讀的文本是ASCII字符來每個ASCII字符需要8bit或1字就能表示。而且使是常用的字符也遠少於65,536,也就是用16bit編碼方式就能表常用字符。但是,有其它更好的編碼方法
可以将一个符文序列表示为一个int32序列。这种编码方式叫UTF-32或UCS-4Unicode码点都使用同的大小32bit表示。这种方式比较简单统一,但是它会浪费很多存储空间,因为大数据计算机可读的文本是ASCII字符来每个ASCII字符需要8bit或1字就能表示。而且使是常用的字符也远少于65,536,也就是用16bit编码方式就能表常用字符。但是,有其它更好的编码方法

View File

@@ -1,6 +1,6 @@
### 3.5.3. UTF-8
UTF8是一個將Unicode碼點編碼爲字節序列的變長編碼。UTF8編碼由Go言之父Ken Thompson和Rob Pike共同明的,在已是Unicode的標準。UTF8編碼使用1到4個字節來表示每Unicode碼點ASCII部分字符使用1個字節常用字符部分使用2或3個字節表示。每個符號編碼後第一個字節的高端bit位用表示共有多少編碼個字節。如果第一個字節的高端bit0表示對應7bit的ASCII字符ASCII字符每字符依然是一個字節,和傳統的ASCII編碼兼容。如果第一個字節的高端bit是110則説明需要2個字節;後續的每高端bit都以10開頭。更大的Unicode碼點也是采用似的策略理。
UTF8是一个将Unicode码点编码为字节序列的变长编码。UTF8编码由Go言之父Ken Thompson和Rob Pike共同明的,在已是Unicode的标准。UTF8编码使用1到4个字节来表示每Unicode码点ASCII部分字符使用1个字节常用字符部分使用2或3个字节表示。每个符号编码后第一个字节的高端bit位用表示共有多少编码个字节。如果第一个字节的高端bit0表示对应7bit的ASCII字符ASCII字符每字符依然是一个字节,和传统的ASCII编码兼容。如果第一个字节的高端bit是110则说明需要2个字节;后续的每高端bit都以10开头。更大的Unicode码点也是采用似的策略理。
```
0xxxxxxx runes 0-127 (ASCII)
@@ -9,11 +9,11 @@ UTF8是一個將Unicode碼點編碼爲字節序列的變長編碼。UTF8編碼
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536-0x10ffff (other values unused)
```
變長的編碼無法直接通索引來訪問第n字符但是UTF8編碼獲得了很多外的優點。首先UTF8編碼比較緊湊完全兼容ASCII碼,併且可以自同步:它可以通向前朔最多2個字節就能確定當前字符編碼的開始字的位置。它也是一個前綴編碼,所以當從左向右解碼時不會有任何歧義也併不需要向前看(譯註像GBK之類的編碼,如果不知道起位置可能會出現歧義)。有任何字符的編碼是其它字符編碼的子串,或是其它編碼序列的字串,因此索一字符時隻要蒐索它的字節編碼序列可,不用心前的上下文會對蒐索結果産生榦擾。同UTF8編碼的順序和Unicode碼點的順序一致因此可以直接排序UTF8編碼序列。同時因爲沒有嵌入的NUL(0)字可以很好地兼容那些使用NUL作字符串尾的編程語言。
变长的编码无法直接通索引来访问第n字符但是UTF8编码获得了很多外的优点。首先UTF8编码比较紧凑完全兼容ASCII码,并且可以自同步:它可以通向前朔最多2个字节就能确定当前字符编码的开始字的位置。它也是一个前缀编码,所以当从左向右解码时不会有任何歧义也并不需要向前看(译注像GBK之类的编码,如果不知道起位置可能会出现歧义)。有任何字符的编码是其它字符编码的子串,或是其它编码序列的字串,因此索一字符时只要搜索它的字节编码序列可,不用心前的上下文会对搜索结果产生干扰。同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編碼。例如:下面的字母串面值都表示相同的值:
有很多Unicode字符很直接从键盘输入,并且还有很多字符有着相似的结构;有一些甚至是不可的字符(译注中文和日文就有很多相似但不同的字。Go言字符串面值中的Unicode转义字符让我们可以通Unicode码点输入特殊的字符。有两种形式:\uhhhh对应16bit的码点值,\Uhhhhhhhh对应32bit的码点其中h是一十六进制数一般很少需要使用32bit的形式。每一个对应码点的UTF8编码。例如:下面的字母串面值都表示相同的值:
```
"世界"
@@ -22,17 +22,17 @@ Go語言的源文件采用UTF8編碼併且Go語言處理UTF8編碼的文本
"\U00004e16\U0000754c"
```
上面三個轉義序列都第一字符串提供替代法,但是它的值都是相同的。
上面三个转义序列都第一字符串提供替代法,但是它的值都是相同的。
Unicode轉義也可以使用在rune字符中。下面三字符是等的:
Unicode转义也可以使用在rune字符中。下面三字符是等的:
```
'世' '\u4e16' '\U00004e16'
```
對於小於256碼點值可以在一十六進製轉義字節中,例如'\x41'對應字符'A',但是對於更大的碼點則必須使用\u或\U轉義形式。因此,'\xe4\xb8\x96'不是一合法的rune字符雖然這三個字節對應一個有效的UTF8編碼的碼點
对于小于256码点值可以在一十六进制转义字节中,例如'\x41'对应字符'A',但是对于更大的码点则必须使用\u或\U转义形式。因此,'\xe4\xb8\x96'不是一合法的rune字符虽然这三个字节对应一个有效的UTF8编码的码点
得益UTF8編碼優良的設計,諸多字符串操作都不需要解操作。我可以不用解直接測試一個字符串是否是另一字符串的前
得益UTF8编码优良的设计,诸多字符串操作都不需要解操作。我可以不用解直接测试一个字符串是否是另一字符串的前
```Go
func HasPrefix(s, prefix string) bool {
@@ -40,7 +40,7 @@ func HasPrefix(s, prefix string) bool {
}
```
或者是後綴測試
或者是后缀测试
```Go
func HasSuffix(s, suffix string) bool {
@@ -48,7 +48,7 @@ func HasSuffix(s, suffix string) bool {
}
```
或者是包含子串測試
或者是包含子串测试
```Go
func Contains(s, substr string) bool {
@@ -61,9 +61,9 @@ func Contains(s, substr string) bool {
}
```
對於UTF8編碼後文本的理和原始的字節處理邏輯是一的。但是對應很多其它編碼則併不是這樣的。(上面的函數都來自strings字符串理包,眞實的代包含了一用哈希技術優化的Contains 實現。)
对于UTF8编码后文本的理和原始的字节处理逻辑是一的。但是对应很多其它编码则并不是这样的。(上面的函数都来自strings字符串理包,真实的代包含了一用哈希技术优化的Contains 实现。)
另一方面,如果我們眞的關心每Unicode字符可以使用其它理方式。考前面的第一例子中的字符串,它包混合了中西兩種字符。3.5展示了它的存表示形式。字符串包含13個字節以UTF8形式編碼,但是隻對應9個Unicode字符
另一方面,如果我们真的关心每Unicode字符可以使用其它理方式。考前面的第一例子中的字符串,它包混合了中西两种字符。3.5展示了它的存表示形式。字符串包含13个字节以UTF8形式编码,但是只对应9个Unicode字符
```Go
import "unicode/utf8"
@@ -73,7 +73,7 @@ fmt.Println(len(s)) // "13"
fmt.Println(utf8.RuneCountInString(s)) // "9"
```
爲了處理這些眞實的字符,我需要一UTF8解器。unicode/utf8包提供了功能,我可以這樣使用:
为了处理这些真实的字符,我需要一UTF8解器。unicode/utf8包提供了功能,我可以这样使用:
```Go
for i := 0; i < len(s); {
@@ -83,7 +83,7 @@ for i := 0; i < len(s); {
}
```
每一次調用DecodeRuneInString函都返迴一個r和r對應字符本身,長度對應r采用UTF8編碼後的編碼字節數目。度可以用更新第i字符在字符串中的字索引位置。但是這種編碼方式是笨拙的,我需要更簡潔的語法。幸的是Go言的range循環在處理字符串的候,會自動隱式解UTF8字符串。下面的循環運行如3.5所示;需要意的是對於非ASCII索引更新的步長將超過1個字節
每一次用DecodeRuneInString函都返回一个r和r对应字符本身,长度对应r采用UTF8编码后的编码字节数目。度可以用更新第i字符在字符串中的字索引位置。但是这种编码方式是笨拙的,我需要更简洁的语法。幸的是Go言的range循环在处理字符串的候,会自动隐式解UTF8字符串。下面的循环运行如3.5所示;需要意的是对于非ASCII索引更新的步长将超过1个字节
![](../images/ch3-05.png)
@@ -93,7 +93,7 @@ for i, r := range "Hello, 世界" {
}
```
可以使用一個簡單的循環來統計字符串中字符的目,像這樣
可以使用一个简单的循环来统计字符串中字符的目,像这样
```Go
n := 0
@@ -102,7 +102,7 @@ for _, _ = range s {
}
```
像其它形式的循環那樣,我也可以忽略不需要的量:
像其它形式的循环那样,我也可以忽略不需要的量:
```Go
n := 0
@@ -111,15 +111,15 @@ for range s {
}
```
或者我可以直接調用utf8.RuneCountInString(s)函
或者我可以直接用utf8.RuneCountInString(s)函
正如我前面提到的文本字符串采用UTF8編碼隻是一種慣例,但是對於循環的眞正字符串不是一個慣例,是正的。如果用於循環的字符串是一普通的二進製數據,或者是含有錯誤編碼的UTF8數據,將會發送什呢?
正如我前面提到的文本字符串采用UTF8编码只是一种惯例,但是对于循环的真正字符串不是一个惯例,是正的。如果用于循环的字符串是一普通的二进制数据,或者是含有错误编码的UTF8数据,将会发送什呢?
每一UTF8字符解,不管是式地調用utf8.DecodeRuneInString解或是在range循環中隱式地解,如果遇到一個錯誤的UTF8編碼輸入,生成一特别的Unicode字符'\uFFFD',在印刷中這個符號通常是一黑色六角或石形,里面包含一白色的問號"<22>"。程序遇到這樣的一字符,通常是一個危險信號,説明輸入併不是一完美沒有錯誤的UTF8字符串。
每一UTF8字符解,不管是式地用utf8.DecodeRuneInString解或是在range循环中隐式地解,如果遇到一个错误的UTF8编码输入,生成一特别的Unicode字符'\uFFFD',在印刷中这个符号通常是一黑色六角或石形,里面包含一白色的问号"<22>"。程序遇到这样的一字符,通常是一个危险信号,说明输入并不是一完美没有错误的UTF8字符串。
UTF8字符串作爲交換格式是非常方便的,但是在程序部采用rune序列可能更方便rune大小一致支持數組索引和方便切割。
UTF8字符串作为交换格式是非常方便的,但是在程序部采用rune序列可能更方便rune大小一致支持数组索引和方便切割。
string接受到[]rune的類型轉換,可以將一個UTF8編碼的字符串解碼爲Unicode字符序列
string接受到[]rune的类型转换,可以将一个UTF8编码的字符串解码为Unicode字符序列
```Go
// "program" in Japanese katakana
@@ -129,22 +129,22 @@ r := []rune(s)
fmt.Printf("%x\n", r) // "[30d7 30ed 30b0 30e9 30e0]"
```
(在第一Printf中的`% x`參數用於在每十六進製數字前插入一空格。)
(在第一Printf中的`% x`参数用于在每十六进制数字前插入一空格。)
如果是將一個[]rune型的Unicode字符slice或數組轉爲string則對它們進行UTF8編碼
如果是将一个[]rune型的Unicode字符slice或数组转为string则对它们进行UTF8编码
```Go
fmt.Println(string(r)) // "プログラム"
```
將一個整數轉型爲字符串意思是生成以包含對應Unicode碼點字符的UTF8字符串
将一个整数转型为字符串意思是生成以包含对应Unicode码点字符的UTF8字符串
```Go
fmt.Println(string(65)) // "A", not "65"
fmt.Println(string(0x4eac)) // "京"
```
如果對應碼點的字符是效的,用'\uFFFD'效字符作爲替換
如果对应码点的字符是效的,用'\uFFFD'效字符作为替换
```Go
fmt.Println(string(1234567)) // "<22>"

View File

@@ -1,14 +1,14 @@
### 3.5.4. 字符串和Byte切片
標準庫中有四個包對字符串理尤重要bytes、strings、strconv和unicode包。strings包提供了多如字符串的査詢、替、比、截、拆分和合等功能。
标准库中有四个包对字符串理尤重要bytes、strings、strconv和unicode包。strings包提供了多如字符串的查询、替、比、截、拆分和合等功能。
bytes包也提供了很多似功能的函,但是針對和字符串有着相同結構的[]byte型。因字符串是隻讀的,因此逐步建字符串會導致很多分配和複製。在這種情況使用bytes.Buffer類型將會更有效,稍後我們將展示。
bytes包也提供了很多似功能的函,但是针对和字符串有着相同结构的[]byte型。因字符串是只读的,因此逐步建字符串会导致很多分配和复制。在这种情况使用bytes.Buffer类型将会更有效,稍后我们将展示。
strconv包提供了布型、整型、浮點數和對應字符串的相互轉換,還提供了雙引號轉義相關的轉換
strconv包提供了布型、整型、浮点数和对应字符串的相互转换,还提供了双引号转义相关的转换
unicode包提供了IsDigit、IsLetter、IsUpper和IsLower等似功能,它們用於給字符分。每個函數有一個單一的rune型的參數,然後返迴一個布爾值。而像ToUpper和ToLower之類的轉換函數將用於rune字符的大小寫轉換。所有的些函都是遵循Unicode標準定義的字母、字等分類規范。strings包也有似的函,它是ToUpper和ToLower原始字符串的每字符都做相應的轉換,然後返迴新的字符串。
unicode包提供了IsDigit、IsLetter、IsUpper和IsLower等似功能,它们用于给字符分。每个函数有一个单一的rune型的参数,然后返回一个布尔值。而像ToUpper和ToLower之类的转换函数将用于rune字符的大小写转换。所有的些函都是遵循Unicode标准定义的字母、字等分类规范。strings包也有似的函,它是ToUpper和ToLower原始字符串的每字符都做相应的转换,然后返回新的字符串。
下面例子的basename函數靈感於Unix shell的同名工具。在我們實現的版本中basename(s)看起像是繫統路徑的前綴刪除,同時將看似文件型的後綴名部分除:
下面例子的basename函数灵感于Unix shell的同名工具。在我们实现的版本中basename(s)看起像是系统路径的前缀删除,同时将看似文件型的后缀名部分除:
```Go
fmt.Println(basename("a/b/c.go")) // "c"
@@ -16,7 +16,7 @@ fmt.Println(basename("c.d.go")) // "c.d"
fmt.Println(basename("abc")) // "abc"
```
第一版本併沒有使用任何,全部手工硬編碼實現
第一版本并没有使用任何,全部手工硬编码实现
<u><i>gopl.io/ch3/basename1</i></u>
```Go
@@ -41,7 +41,7 @@ func basename(s string) string {
}
```
簡化個版本使用了strings.LastIndex庫函數
简化个版本使用了strings.LastIndex库函数
<u><i>gopl.io/ch3/basename2</i></u>
```Go
@@ -55,9 +55,9 @@ func basename(s string) string {
}
```
path和path/filepath包提供了關於文件路名更一般的函操作。使用斜分隔路可以在任何操作繫統上工作。斜本身不應該用於文件名,但是在其他一些域可能會用於文件名例如URL路徑組件。相比之下path/filepath包使用操作繫統本身的路徑規則例如POSIX繫統使用/foo/bar而Microsoft Windows使用c:\foo\bar等。
path和path/filepath包提供了关于文件路名更一般的函操作。使用斜分隔路可以在任何操作系统上工作。斜本身不应该用于文件名,但是在其他一些域可能会用于文件名例如URL路径组件。相比之下path/filepath包使用操作系统本身的路径规则例如POSIX系统使用/foo/bar而Microsoft Windows使用c:\foo\bar等。
讓我們繼續另一字符串的例子。函的功能是將一個表示整值的字符串,每隔三字符插入一個逗號分隔符例如“12345”處理後成爲“12,345”。這個版本隻適用於整數類型;支持浮點數類型的支持留作練習
让我们继续另一字符串的例子。函的功能是将一个表示整值的字符串,每隔三字符插入一个逗号分隔符例如“12345”处理后成为“12,345”。这个版本只适用于整数类型;支持浮点数类型的支持留作练习
<u><i>gopl.io/ch3/comma</i></u>
```Go
@@ -71,11 +71,11 @@ func comma(s string) string {
}
```
入comma函數的參數是一字符串。如果入字符串的度小或等3的話,則不需要插入逗分隔符。否comma函數將在最後三個字符前位置字符串切割爲兩個兩個子串插入逗分隔符,然後通過遞歸調用自身出前面的子串。
入comma函数的参数是一字符串。如果入字符串的度小或等3的话,则不需要插入逗分隔符。否comma函数将在最后三个字符前位置字符串切割为两个两个子串插入逗分隔符,然后通过递归调用自身出前面的子串。
字符串是包含的隻讀字節數組,一旦建,是不可的。相比之下,一個字節slice的元素可以自由地改。
字符串是包含的只读字节数组,一旦建,是不可的。相比之下,一个字节slice的元素可以自由地改。
字符串和字slice之可以相互轉換
字符串和字slice之可以相互转换
```Go
s := "abc"
@@ -83,9 +83,9 @@ b := []byte(s)
s2 := string(b)
```
概念上,一[]byte(s)轉換是分配了一新的字節數組用於保存字符串數據的拷,然引用這個底層的字節數組。編譯器的化可以避免在一些景下分配和複製字符串數據,但總的來説需要保在量b被改的情原始的s字符串也不會改變。將一個字節slice到字符串的string(b)操作則是構造一字符串拷,以保s2字符串是隻讀的。
概念上,一[]byte(s)转换是分配了一新的字节数组用于保存字符串数据的拷,然引用这个底层的字节数组。编译器的化可以避免在一些景下分配和复制字符串数据,但总的来说需要保在量b被改的情原始的s字符串也不会改变。将一个字节slice到字符串的string(b)操作则是构造一字符串拷,以保s2字符串是只读的。
了避免轉換中不必要的存分配bytes包和strings同提供了許多實用函。下面是strings包中的六個函數
了避免转换中不必要的存分配bytes包和strings同提供了许多实用函。下面是strings包中的六个函数
```Go
func Contains(s, substr string) bool
@@ -96,7 +96,7 @@ func Index(s, sep string) int
func Join(a []string, sep string) string
```
bytes包中也對應的六個函數
bytes包中也对应的六个函数
```Go
func Contains(b, subslice []byte) bool
@@ -107,9 +107,9 @@ func Index(s, sep []byte) int
func Join(s [][]byte, sep []byte) []byte
```
們之間唯一的别是字符串類型參數被替成了字slice型的參數
们之间唯一的别是字符串类型参数被替成了字slice型的参数
bytes包提供了Buffer型用於字節slice的存。一Buffer始是空的,但是着string、byte或[]byte等類型數據的寫入可以動態增長,一bytes.Buffer變量併不需要理化,因零值也是有效的:
bytes包提供了Buffer型用于字节slice的存。一Buffer始是空的,但是着string、byte或[]byte等类型数据的写入可以动态增长,一bytes.Buffer变量并不需要理化,因零值也是有效的:
<u><i>gopl.io/ch3/printints</i></u>
```Go
@@ -132,12 +132,12 @@ func main() {
}
```
向bytes.Buffer添加任意字符的UTF8編碼時最好使用bytes.Buffer的WriteRune方法但是WriteByte方法對於寫入類似'['和']'等ASCII字符則會更加有效。
向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代替字符串接操作。
**练习 3.10** 编写一个非递归版本的comma函使用bytes.Buffer代替字符串接操作。
**練習 3.11** 完善comma函,以支持浮點數處理和一個可選的正負號的處理。
**练习 3.11** 完善comma函,以支持浮点数处理和一个可选的正负号的处理。
**練習 3.12** 編寫一個函數,判斷兩個字符串是否是是相互打的,也就是説它們有着相同的字符,但是對應不同的序。
**练习 3.12** 编写一个函数,判断两个字符串是否是是相互打的,也就是说它们有着相同的字符,但是对应不同的序。

View File

@@ -1,8 +1,8 @@
### 3.5.5. 字符串和字的轉換
### 3.5.5. 字符串和字的转换
除了字符串、字符、字節之間的轉換,字符串和值之間的轉換也比較常見。由strconv包提供這類轉換功能。
除了字符串、字符、字节之间的转换,字符串和值之间的转换也比较常见。由strconv包提供这类转换功能。
將一個整數轉爲字符串,一方法是用fmt.Sprintf返迴一個格式化的字符串;另一方法是用strconv.Itoa(“整到ASCII”)
将一个整数转为字符串,一方法是用fmt.Sprintf返回一个格式化的字符串;另一方法是用strconv.Itoa(“整到ASCII”)
```Go
x := 123
@@ -10,28 +10,28 @@ y := fmt.Sprintf("%d", x)
fmt.Println(y, strconv.Itoa(x)) // "123 123"
```
FormatInt和FormatUint函可以用不同的進製來格式化字:
FormatInt和FormatUint函可以用不同的进制来格式化字:
```Go
fmt.Println(strconv.FormatInt(int64(x), 2)) // "1111011"
```
fmt.Printf函的%b、%d、%o和%x等參數提供功能往往比strconv包的Format函方便很多,特别是在需要包含附加外信息的候:
fmt.Printf函的%b、%d、%o和%x等参数提供功能往往比strconv包的Format函方便很多,特别是在需要包含附加外信息的候:
```Go
s := fmt.Sprintf("x=%b", x) // "x=1111011"
```
如果要將一個字符串解析爲整數可以使用strconv包的Atoi或ParseInt函數,還有用解析無符號整數的ParseUint函
如果要将一个字符串解析为整数可以使用strconv包的Atoi或ParseInt函数,还有用解析无符号整数的ParseUint函
```Go
x, err := strconv.Atoi("123") // x is an int
y, err := strconv.ParseInt("123", 10, 64) // base 10, up to 64 bits
```
ParseInt函的第三個參數是用指定整型的大小例如16表示int160表示int。在任何情下,返迴的結果y是int64型,你可以通過強製類型轉換將它轉爲更小的整數類型。
ParseInt函的第三个参数是用指定整型的大小例如16表示int160表示int。在任何情下,返回的结果y是int64型,你可以通过强制类型转换将它转为更小的整数类型。
候也使用fmt.Scanf解析入的字符串和字,特别是字符串和字混合在一行的候,它可以靈活處理不完整或不規則的輸入。
候也使用fmt.Scanf解析入的字符串和字,特别是字符串和字混合在一行的候,它可以灵活处理不完整或不规则的输入。

View File

@@ -1,8 +1,8 @@
## 3.5. 字符串
字符串是一不可改的字序列。字符串可以包含任意的數據包括byte值0但是通常是用包含人類可讀的文本。文本字符串通常被解釋爲采用UTF8編碼的Unicode碼點rune序列們稍後會詳細討論這個問題
字符串是一不可改的字序列。字符串可以包含任意的数据包括byte值0但是通常是用包含人类可读的文本。文本字符串通常被解释为采用UTF8编码的Unicode码点rune序列们稍后会详细讨论这个问题
置的len函可以返迴一個字符串中的字節數不是rune字符索引操作s[i]返第i個字節的字i必須滿足0 ≤ i< len(s)條件約
置的len函可以返回一个字符串中的字节数不是rune字符索引操作s[i]返第i个字节的字i必须满足0 ≤ i< len(s)条件约
```Go
s := "hello, world"
@@ -10,23 +10,23 @@ 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
```
第i個字節併不一定是字符串的第i字符爲對於非ASCII字符的UTF8編碼會要兩個或多個字節們先簡單説下字符的工作方式
第i个字节并不一定是字符串的第i字符为对于非ASCII字符的UTF8编码会要两个或多个字节们先简单说下字符的工作方式
子字符串操作s[i:j]原始的s字符串的第i個字節開始到第j個字節不包含j本身生成一新字符串生成的新字符串包含j-i個字節
子字符串操作s[i:j]原始的s字符串的第i个字节开始到第j个字节不包含j本身生成一新字符串生成的新字符串包含j-i个字节
```Go
fmt.Println(s[0:5]) // "hello"
```
如果索引超出字符串范或者j小i的話將導致panic
如果索引超出字符串范或者j小i的话将导致panic
不管i是j都可能被忽略當它們被忽略時將采用0作爲開始位置采用len(s)爲結束的位置
不管i是j都可能被忽略当它们被忽略时将采用0作为开始位置采用len(s)为结束的位置
```Go
fmt.Println(s[:5]) // "hello"
@@ -34,15 +34,15 @@ fmt.Println(s[7:]) // "world"
fmt.Println(s[:]) // "hello, world"
```
其中+操作符將兩個字符串鏈接構造一新字符串
其中+操作符将两个字符串链接构造一新字符串
```Go
fmt.Println("goodbye" + s[5:]) // "goodbye, world"
```
字符串可以用==和<行比;比較通過逐個字節比較完成的,因此比較的結果是字符串自然編碼的順序。
字符串可以用==和<行比;比较通过逐个字节比较完成的,因此比较的结果是字符串自然编码的顺序。
字符串的值是不可字符串包含的字序列永遠不會被改然我也可以給一個字符串量分配一新字符串值可以像下面這樣將一個字符串追加到另一字符串
字符串的值是不可字符串包含的字序列永远不会被改然我也可以给一个字符串量分配一新字符串值可以像下面这样将一个字符串追加到另一字符串
```Go
s := "left foot"
@@ -50,20 +50,20 @@ t := s
s += ", right foot"
```
這併不會導致原始的字符串值被改但是量s將因爲+=句持有一新的字符串值但是t依然是包含原先的字符串值
这并不会导致原始的字符串值被改但是量s将因为+=句持有一新的字符串值但是t依然是包含原先的字符串值
```Go
fmt.Println(s) // "left foot, right foot"
fmt.Println(t) // "left foot"
```
字符串是不可改的因此嚐試脩改字符串內部數據的操作也是被禁止的
字符串是不可改的因此尝试修改字符串内部数据的操作也是被禁止的
```Go
s[0] = 'L' // compile error: cannot assign to s[0]
```
性意味如果兩個字符串共享相同的底層數據的話也是安全的使得複製任何度的字符串代是低廉的字符串s和對應的子字符串切片s[7:]的操作也可以安全地共享相同的因此字符串切片操作代也是低廉的這兩種情況下都有必要分配新的 3.4演示了一字符串和兩個字串共享相同的底層數據
性意味如果两个字符串共享相同的底层数据的话也是安全的使得复制任何度的字符串代是低廉的字符串s和对应的子字符串切片s[7:]的操作也可以安全地共享相同的因此字符串切片操作代也是低廉的这两种情况下都有必要分配新的 3.4演示了一字符串和两个字串共享相同的底层数据
{% include "./ch3-05-1.md" %}

View File

@@ -1,8 +1,8 @@
### 3.6.1. iota 常量生成器
常量明可以使用iota常量生成器初始化它用生成一以相似規則初始化的常量,但是不用每行都一遍初始化表式。在一const聲明語句中,在第一個聲明的常量所在的行iota將會被置0在每一有常量明的行加一。
常量明可以使用iota常量生成器初始化它用生成一以相似规则初始化的常量,但是不用每行都一遍初始化表式。在一const声明语句中,在第一个声明的常量所在的行iota将会被置0在每一有常量明的行加一。
下面是自time包的例子它首先定了一Weekday命名型,然後爲一週的每天定了一常量,從週日0始。在其它編程語言中,這種類型一般被稱爲枚舉類型。
下面是自time包的例子它首先定了一Weekday命名型,然后为一周的每天定了一常量,从周日0始。在其它编程语言中,这种类型一般被称为枚举类型。
```Go
type Weekday int
@@ -18,9 +18,9 @@ const (
)
```
週一將對應0週一爲1如此等等。
周一将对应0周一为1如此等等。
也可以在複雜的常量表式中使用iota下面是自net包的例子於給一個無符號整數的最低5bit的每bit指定一名字:
也可以在复杂的常量表式中使用iota下面是自net包的例子于给一个无符号整数的最低5bit的每bit指定一名字:
```Go
type Flags uint
@@ -34,7 +34,7 @@ const (
)
```
着iota的增,每常量對應表達式1 << iota連續的2的分别對應一個bit位置使用些常量可以用於測試置或清除對應的bit位的值
着iota的增,每常量对应表达式1 << iota连续的2的分别对应一个bit位置使用些常量可以用于测试置或清除对应的bit位的值
<u><i>gopl.io/ch3/netflag</i></u>
```Go
@@ -54,7 +54,7 @@ unc main() {
}
```
下面是一個更複雜的例子,每常量都是1024的
下面是一个更复杂的例子,每常量都是1024的
```Go
const (
@@ -70,6 +70,6 @@ const (
)
```
iota常量生成規則也有其局限性。例如,它不能用於産生1000的KB、MB等Go語言併沒有計算冪的運算符。
iota常量生成规则也有其局限性。例如,它不能用于产生1000的KB、MB等Go语言并没有计算幂的运算符。
**練習 3.13** 編寫KB、MB的常量明,然後擴展到YB。
**练习 3.13** 编写KB、MB的常量明,然后扩展到YB。

View File

@@ -1,14 +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言中整数类型能表的范,但是它依然是合法的常量,而且可以像下面常量表式依然有效(译注YiB/ZiB是在编译期计算出的,并且结果常量是1024是Go言int量能有效表示的):
```Go
fmt.Println(YiB/ZiB) // "1024"
```
另一例子math.Pi無類型的浮點數常量,可以直接用任意需要浮點數或複數的地方:
另一例子math.Pi无类型的浮点数常量,可以直接用任意需要浮点数或复数的地方:
```Go
var x float32 = math.Pi
@@ -16,7 +16,7 @@ var y float64 = math.Pi
var z complex128 = math.Pi
```
如果math.Pi被確定爲特定比如float64麽結果精度可能不一,同時對於需要float32或complex128型值的地方則會強製需要一個明確的類型轉換
如果math.Pi被确定为特定比如float64么结果精度可能不一,同时对于需要float32或complex128型值的地方则会强制需要一个明确的类型转换
```Go
const Pi64 float64 = math.Pi
@@ -26,9 +26,9 @@ var y float64 = Pi64
var z complex128 = complex128(Pi64)
```
對於常量面值,不同的法可能會對應不同的型。例如0、0.0、0i和'\u0000'然有着相同的常量值,但是它分别對應無類型的整數、無類型的浮點數、無類型的複數和無類型的字符等不同的常量型。同true和false也是無類型的布爾類型,字符串面值常量是無類型的字符串型。
对于常量面值,不同的法可能会对应不同的型。例如0、0.0、0i和'\u0000'然有着相同的常量值,但是它分别对应无类型的整数、无类型的浮点数、无类型的复数和无类型的字符等不同的常量型。同true和false也是无类型的布尔类型,字符串面值常量是无类型的字符串型。
前面説過除法算符/會根據操作數的類型生成對應類型的果。因此,不同法的常量除法表式可能對應不同的果:
前面说过除法算符/会根据操作数的类型生成对应类型的果。因此,不同法的常量除法表式可能对应不同的果:
```Go
var f float64 = 212
@@ -37,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
```
有常量可以是無類型的。當一個無類型的常量被賦值給一個變量的候,就像上面的第一行句,或者是像其餘三個語句中右邊表達式中含有明確類型的值,無類型的常量將會被隱式轉換爲對應的類型,如果轉換合法的
有常量可以是无类型的。当一个无类型的常量被赋值给一个变量的候,就像上面的第一行句,或者是像其余三个语句中右边表达式中含有明确类型的值,无类型的常量将会被隐式转换为对应的类型,如果转换合法的
```Go
var f float64 = 3 + 0i // untyped complex -> float64
@@ -46,7 +46,7 @@ f = 1e123 // untyped floating-point -> float64
f = 'a' // untyped rune -> float64
```
上面的句相當於:
上面的句相当于:
```Go
var f float64 = float64(3 + 0i)
@@ -55,7 +55,7 @@ f = float64(1e123)
f = float64('a')
```
無論是隱式或顯式轉換,將一種類型轉換爲另一種類型都要求目可以表示原始值。對於浮點數和複數,可能有舍入理:
无论是隐式或显式转换,将一种类型转换为另一种类型都要求目可以表示原始值。对于浮点数和复数,可能有舍入理:
```Go
const (
@@ -69,7 +69,7 @@ const (
)
```
對於一個沒有顯式類型的變量聲明語法(包括短變量聲明語法),無類型的常量會被隱式轉爲默認的變量類型,就像下面的例子:
对于一个没有显式类型的变量声明语法(包括短变量声明语法),无类型的常量会被隐式转为默认的变量类型,就像下面的例子:
```Go
i := 0 // untyped integer; implicit int(0)
@@ -78,16 +78,16 @@ 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言本身并没有不确定内存大小的浮点数和复数类型,而且如果不知道浮点数类型的话将很难写出正确的数值算法。
如果要給變量一不同的型,我們必須顯式地將無類型的常量轉化爲所需的型,或給聲明的量指定明確的類型,像下面例子這樣
如果要给变量一不同的型,我们必须显式地将无类型的常量转化为所需的型,或给声明的量指定明确的类型,像下面例子这样
```Go
var i = int8(0)
var i int8 = 0
```
當嚐試將這些無類型的常量轉爲一個接口值時(見第7章些默認類型將顯得尤重要,因要靠它們明確接口對應的動態類型。
当尝试将这些无类型的常量转为一个接口值时(见第7章些默认类型将显得尤重要,因要靠它们明确接口对应的动态类型。
```Go
fmt.Printf("%T\n", 0) // "int"
@@ -96,7 +96,7 @@ fmt.Printf("%T\n", 0i) // "complex128"
fmt.Printf("%T\n", '\000') // "int32" (rune)
```
在我們已經講述了Go言中全部的基礎數據類型。下一步演示如何用基礎數據類型組合成數組或結構體等複雜數據類型,然後構建用於解決實際編程問題的數據結構,這將是第四章的討論主題
在我们已经讲述了Go言中全部的基础数据类型。下一步演示如何用基础数据类型组合成数组或结构体等复杂数据类型,然后构建用于解决实际编程问题的数据结构,这将是第四章的讨论主题

View File

@@ -1,14 +1,14 @@
## 3.6. 常量
常量表式的值在編譯期計算,而不是在行期。每常量的潛在類型都是基礎類boolean、string或字。
常量表式的值在编译期计算,而不是在行期。每常量的潜在类型都是基础类boolean、string或字。
常量的聲明語句定了常量的名字,和量的聲明語法類似,常量的值不可改,這樣可以防止在行期被意外或意的改。例如,常量比量更合用於表達像π之類的數學常數,因爲它們的值不會發生變化:
常量的声明语句定了常量的名字,和量的声明语法类似,常量的值不可改,这样可以防止在行期被意外或意的改。例如,常量比量更合用于表达像π之类的数学常数,因为它们的值不会发生变化:
```Go
const pi = 3.14159 // approximately; math.Pi is a better approximation
```
變量聲明一,可以批量明多常量;這比較適合聲明一組相關的常量:
变量声明一,可以批量明多常量;这比较适合声明一组相关的常量:
```Go
const (
@@ -17,11 +17,11 @@ const (
)
```
所有常量的算都可以在編譯期完成,這樣可以減少運行時的工作,也方便其他編譯優化。操作是常量,一些運行時的錯誤也可以在編譯時被發現,例如整除零、字符串索引越界、任何導致無效浮點數的操作等。
所有常量的算都可以在编译期完成,这样可以减少运行时的工作,也方便其他编译优化。操作是常量,一些运行时的错误也可以在编译时被发现,例如整除零、字符串索引越界、任何导致无效浮点数的操作等。
常量的所有算術運算、邏輯運算和比較運算的果也是常量,常量的類型轉換操作或以下函數調用都是返常量len、cap、real、imag、complex和unsafe.Sizeof§13.1)。
常量的所有算术运算、逻辑运算和比较运算的果也是常量,常量的类型转换操作或以下函数调用都是返常量len、cap、real、imag、complex和unsafe.Sizeof§13.1)。
爲它們的值是在編譯期就定的,因此常量可以是構成類型的一部分,例如用指定數組類型的度:
为它们的值是在编译期就定的,因此常量可以是构成类型的一部分,例如用指定数组类型的度:
```Go
const IPv4Len = 4
@@ -33,7 +33,7 @@ func parseIPv4(s string) IP {
}
```
常量的明也可以包含一個類型和一值,但是如果沒有顯式指明型,那麽將從右邊的表式推斷類型。在下面的代time.Duration是一命名型,底層類型是int64time.Minute是對應類型的常量。下面明的兩個常量都是time.Duration型,可以通%T參數打印型信息:
常量的明也可以包含一个类型和一值,但是如果没有显式指明型,那么将从右边的表式推断类型。在下面的代time.Duration是一命名型,底层类型是int64time.Minute是对应类型的常量。下面明的两个常量都是time.Duration型,可以通%T参数打印型信息:
```Go
const noDelay time.Duration = 0
@@ -43,7 +43,7 @@ fmt.Printf("%T %[1]v\n", timeout) // "time.Duration 5m0s"
fmt.Printf("%T %[1]v\n", time.Minute) // "time.Duration 1m0s"
```
如果是批量明的常量,除了第一外其它的常量右的初始化表式都可以省略,如果省略初始化表達式則表示使用前面常量的初始化表達式寫法,對應的常量型也一的。例如:
如果是批量明的常量,除了第一外其它的常量右的初始化表式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式写法,对应的常量型也一的。例如:
```Go
const (
@@ -56,7 +56,7 @@ const (
fmt.Println(a, b, c, d) // "1 1 2 2"
```
如果隻是簡單地複製右邊的常量表式,其實併沒有太用的值。但是它可以帶來其它的特性那就是iota常量生成器法。
如果只是简单地复制右边的常量表式,其实并没有太用的值。但是它可以带来其它的特性那就是iota常量生成器法。
{% include "./ch3-06-1.md" %}

View File

@@ -1,5 +1,5 @@
# 第3章 基礎數據類
# 第3章 基础数据类
雖然從底層而言,所有的數據都是由比特成,但計算機一般操作的是固定大小的,如整、浮點數、比特數組、內存地址等。一步將這些數組織在一起,就可表更多的象,例如數據包、像素點、詩歌,甚至其他任何象。Go言提供了富的數據組織形式這依賴於Go語言內置的數據類型。這些內置的數據類型,兼了硬件的特性和表達複雜數據結構的便捷性。
虽然从底层而言,所有的数据都是由比特成,但计算机一般操作的是固定大小的,如整、浮点数、比特数组、内存地址等。一步将这些数组织在一起,就可表更多的象,例如数据包、像素点、诗歌,甚至其他任何象。Go言提供了富的数据组织形式这依赖于Go语言内置的数据类型。这些内置的数据类型,兼了硬件的特性和表达复杂数据结构的便捷性。
Go語言將數據類型分爲四類:基礎類型、複合類型、引用型和接口型。本章介紹基礎類型,包括:字、字符串和布型。複合數據類型——數組§4.1)和結構體§4.2)——是通過組合簡單類型,來表達更加複雜的數據結構。引用型包括指§2.3.2、切片§4.2)字典§4.3)、函§5、通道§8雖然數據種類很多,但它都是程序中一個變量或狀態的間接引用。意味着任一引用類型數據的脩改都會影響所有引用的拷。我們將在第7章介接口型。
Go语言将数据类型分为四类:基础类型、复合类型、引用型和接口型。本章介绍基础类型,包括:字、字符串和布型。复合数据类型——数组§4.1)和结构体§4.2)——是通过组合简单类型,来表达更加复杂的数据结构。引用型包括指§2.3.2、切片§4.2)字典§4.3)、函§5、通道§8虽然数据种类很多,但它都是程序中一个变量或状态的间接引用。意味着任一引用类型数据的修改都会影响所有引用的拷。我们将在第7章介接口型。