mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-10-19 05:22:19 +00:00
make zh2tw
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
## 3.1. 整型
|
||||
|
||||
Go语言的数值类型包括几种不同大小的整形数, 浮点数, 和复数. 每种数值类型都决定了对应的大小范围和是否有正负符号. 让我们先从整形数类型开始介绍.
|
||||
Go語言的數值類型包括幾種不同大小的整形數, 浮點數, 和複數. 每種數值類型都決定了對應的大小范圍和是否有正負符號. 讓我們先從整形數類型開始介紹.
|
||||
|
||||
Go同时提供了有符号和无符号的整数运算. 这里有四种int8, int16, int32 和 int64截然不同大小的有符号整形数类型, 分别对应 8, 16, 32, 64 bit 大小的有符号整形数, 与此对应的是 uint8, uint16, uint32, 和 uint64 四种无符号整形数类型.
|
||||
Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int16, int32 和 int64截然不同大小的有符號整形數類型, 分别對應 8, 16, 32, 64 bit 大小的有符號整形數, 與此對應的是 uint8, uint16, uint32, 和 uint64 四種無符號整形數類型.
|
||||
|
||||
这里还有两种对应特定平台最天然或最有效率的大小有符号和无符号整数int和uint; 其中int是应用最广泛的数值类型. 这两种类型都有同样的大小, 32 或 64 bit, 但是我们不能对此做任何的假设; 因为不同的编译器在相同的硬件平台上可能产生不同的大小.
|
||||
這里還有兩種對應特定平颱最天然或最有效率的大小有符號和無符號整數int和uint; 其中int是應用最廣泛的數值類型. 這兩種類型都有同樣的大小, 32 或 64 bit, 但是我們不能對此做任何的假設; 因爲不同的編譯器在相同的硬件平颱上可能産生不同的大小.
|
||||
|
||||
字符rune类型是和int32等价的类型, 通常用于表示一个Unicode码点. 这两个名称可以互换使用. 同样byte也是uint8类型的等价类型, byte类型用于强调数值是一个原始的数据而不是一个小的整数.
|
||||
字符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的补码形式表示, 也就是最高位用作符号位, 一个nbit的有符号数的值域是 `-2^(n-1)` 到 `(2^(n-1)) - 1`. 无符号整数的所有bit位都用于表示非负数, 值域是 0 到 `(2^n) - 1`. 例如, int8 的值域是 -128 到 127, 而 uint8 的值域是 0 到 255.
|
||||
有符號數采用2的補碼形式表示, 也就是最高位用作符號位, 一個nbit的有符號數的值域是 `-2^(n-1)` 到 `(2^(n-1)) - 1`. 無符號整數的所有bit位都用於表示非負數, 值域是 0 到 `(2^n) - 1`. 例如, int8 的值域是 -128 到 127, 而 uint8 的值域是 0 到 255.
|
||||
|
||||
下面是Go中关于算术, 逻辑和比较的二元运算符按照先级递减的顺序的列表:
|
||||
下面是Go中關於算術, 邏輯和比較的二元運算符按照先級遞減的順序的列表:
|
||||
|
||||
```
|
||||
* / % << >> & &^
|
||||
@@ -24,14 +24,14 @@ Go同时提供了有符号和无符号的整数运算. 这里有四种int8, int1
|
||||
||
|
||||
```
|
||||
|
||||
二元运算符有五种优先级. 在同一优先级, 使用左优先结合律, 使用括号可以明确优先顺序, 括号也可以用于提升优先级, 例如 `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
|
||||
@@ -41,7 +41,7 @@ var i int8 = 127
|
||||
fmt.Println(i, i+1, i*i) // "127 -128 1"
|
||||
```
|
||||
|
||||
两个相同的整数类型可以使用下面的二元比较运算符进行比较; 比较表达式的结果是布尔类型.
|
||||
兩個相同的整數類型可以使用下面的二元比較運算符進行比較; 比較表達式的結果是布爾類型.
|
||||
|
||||
```
|
||||
== equal to
|
||||
@@ -52,33 +52,33 @@ 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位1, 如果对应y中bit位为1, 否则对应的bit位等于x相应的bit位的值.
|
||||
位操作運算符 `^` 作爲二元運算符時是按位異或(XOR), 當用作一元運算符時表示按位取反; 也就是説, 它返迴一個每個bit位都取反的數. 位操作運算符 `&^` 用於按位置零(AND NOT): 表達式 `z = x &^ y` 結果z的bit位1, 如果對應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
|
||||
@@ -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.
|
||||
在 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"}
|
||||
@@ -117,13 +117,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), 也就是试图访问一个切片范围以外的元素.
|
||||
另一個選擇將是災難性的. 如果 len 返迴一個無符號數, 那麽 i 也將是無符號的 uint, 然後條件 i >= 0 則永遠爲眞. 在三次迭代之後, 也就是 i == 0 時, i-- 語句將不會産生 -1, 而是變成一個uint的最大值(可能是 2^64 - 1), 然後 medals[i] 表達式將發生運行時 panic 異常(§5.9), 也就是試圖訪問一個切片范圍以外的元素.
|
||||
|
||||
出于这个原因, 无符号数往往只有在位运算或其它特殊的运算常见才会使用, 就像 bit 集合, 分形二进制文件格式, 或者是哈希和加密操作等. 它们通常并不用于仅仅是表达非负数量的场合.
|
||||
齣於這個原因, 無符號數往往隻有在位運算或其它特殊的運算常見纔會使用, 就像 bit 集合, 分形二進製文件格式, 或者是哈希和加密操作等. 它們通常併不用於僅僅是表達非負數量的場合.
|
||||
|
||||
一般来说, 需要一个显式的转换将一个值从一种类型转化位另一种类型, 并且算术和逻辑运算的二元操作中必须是相同的类型. 虽然这偶尔会导致很长的表达式, 但是它消除了所有的类型相关的问题, 也使得程序容易理解.
|
||||
一般來説, 需要一個顯式的轉換將一個值從一種類型轉化位另一種類型, 併且算術和邏輯運算的二元操作中必鬚是相同的類型. 雖然這偶爾會導致很長的表達式, 但是它消除了所有的類型相關的問題, 也使得程序容易理解.
|
||||
|
||||
从其他类似场景下, 考虑下面这个代码:
|
||||
從其他類似場景下, 考慮下面這個代碼:
|
||||
|
||||
```Go
|
||||
var apples int32 = 1
|
||||
@@ -131,19 +131,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
|
||||
@@ -153,16 +153,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
|
||||
@@ -173,18 +173,18 @@ 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'
|
||||
unicode := '国'
|
||||
unicode := '國'
|
||||
newline := '\n'
|
||||
fmt.Printf("%d %[1]c %[1]q\n", ascii) // "97 a 'a'"
|
||||
fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 国 '国'"
|
||||
fmt.Printf("%d %[1]c %[1]q\n", unicode) // "22269 國 '國'"
|
||||
fmt.Printf("%d %[1]q\n", newline) // "10 '\n'"
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user