數字類型
4.5.2.1 整型 int 和浮點型 float
Go 語言支持整型和浮點型數字,並且原生支持複數,其中位的運算採用補碼(詳情參見 二的補碼 頁面)。
Go 也有基於架構的類型,例如:int、uint 和 uintptr。
這些類型的長度都是根據運行程序所在的操作系統類型所決定的:
int
和uint
在 32 位操作系統上,它們均使用 32 位(4 個字節),在 64 位操作系統上,它們均使用 64 位(8 個字節)。uintptr
的長度被設定爲足夠存放一個指針即可。
Go 語言中沒有 float 類型。
與操作系統架構無關的類型都有固定的大小,並在類型的名稱中就可以看出來:
整數:
- int8(-128 -> 127)
- int16(-32768 -> 32767)
- int32(-2,147,483,648 -> 2,147,483,647)
- int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)
無符號整數:
- uint8(0 -> 255)
- uint16(0 -> 65,535)
- uint32(0 -> 4,294,967,295)
- uint64(0 -> 18,446,744,073,709,551,615)
浮點型(IEEE-754 標準):
- float32(+- 1e-45 -> +- 3.4 * 1e38)
- float64(+- 5 * 1e-324 -> 107 * 1e308)
int 型是計算最快的一種類型。
整型的零值爲 0,浮點型的零值爲 0.0。
float32 精確到小數點後 7 位,float64 精確到小數點後 15 位。由於精確度的緣故,你在使用 ==
或者 !=
來比較浮點數時應當非常小心。你最好在正式使用前測試對於精確度要求較高的運算。
你應該儘可能地使用 float64,因爲 math
包中所有有關數學運算的函數都會要求接收這個類型。
你可以通過增加前綴 0 來表示 8 進制數(如:077),增加前綴 0x 來表示 16 進制數(如:0xFF),以及使用 e 來表示 10 的連乘(如: 1e3 = 1000,或者 6.022e23 = 6.022 x 1e23)。
你可以使用 a := uint64(0)
來同時完成類型轉換和賦值操作,這樣 a 的類型就是 uint64。
Go 中不允許不同類型之間的混合使用,但是對於常量的類型限制非常少,因此允許常量之間的混合使用,下面這個程序很好地解釋了這個現象(該程序無法通過編譯):
示例 4.8 type_mixing.go
package main
func main() {
var a int
var b int32
a = 15
b = a + a // 編譯錯誤
b = b + 5 // 因爲 5 是常量,所以可以通過編譯
}
如果你嘗試編譯該程序,則將得到編譯錯誤 cannot use a + a (type int) as type int32 in assignment
。
同樣地,int16 也不能夠被隱式轉換爲 int32。
下面這個程序展示了通過顯式轉換來避免這個問題(第 4.2 節)。
示例 4.9 casting.go
package main
import "fmt"
func main() {
var n int16 = 34
var m int32
// compiler error: cannot use n (type int16) as type int32 in assignment
//m = n
m = int32(n)
fmt.Printf("32 bit int is: %d\n", m)
fmt.Printf("16 bit int is: %d\n", n)
}
輸出:
32 bit int is: 34
16 bit int is: 34
格式化說明符
在格式化字符串裏,%d
用於格式化整數(%x
和 %X
用於格式化 16 進製表示的數字),%g
用於格式化浮點型(%f
輸出浮點數,%e
輸出科學計數表示法),%0d
用於規定輸出定長的整數,其中開頭的數字 0 是必須的。
%n.mg
用於表示數字 n 並精確到小數點後 m 位,除了使用 g 之外,還可以使用 e 或者 f,例如:使用格式化字符串 %5.2e
來輸出 3.4 的結果爲 3.40e+00
。
數字值轉換
當進行類似 a32bitInt = int32(a32Float)
的轉換時,小數點後的數字將被丟棄。這種情況一般發生當從取值範圍較大的類型轉換爲取值範圍較小的類型時,或者你可以寫一個專門用於處理類型轉換的函數來確保沒有發生精度的丟失。下面這個例子展示如何安全地從 int 型轉換爲 int8:
func Uint8FromInt(n int) (uint8, error) {
if 0 <= n && n <= math.MaxUint8 { // conversion is safe
return uint8(n), nil
}
return 0, fmt.Errorf("%d is out of the uint8 range", n)
}
或者安全地從 float64 轉換爲 int:
func IntFromFloat64(x float64) int {
if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
whole, fraction := math.Modf(x)
if fraction >= 0.5 {
whole++
}
return int(whole)
}
panic(fmt.Sprintf("%g is out of the int32 range", x))
}
不過如果你實際存的數字超出你要轉換到的類型的取值範圍的話,則會引發 panic(第 13.2 節)。
問題 4.1 int 和 int64 是相同的類型嗎?
4.5.2.2 複數
Go 擁有以下複數類型:
complex64 (32 位實數和虛數)
complex128 (64 位實數和虛數)
複數使用 re+imI
來表示,其中 re
代表實數部分,im
代表虛數部分,I 代表根號負 1。
示例:
var c1 complex64 = 5 + 10i
fmt.Printf("The value is: %v", c1)
// 輸出: 5 + 10i
如果 re
和 im
的類型均爲 float32,那麼類型爲 complex64 的複數 c 可以通過以下方式來獲得:
c = complex(re, im)
函數 real(c)
和 imag(c)
可以分別獲得相應的實數和虛數部分。
在使用格式化說明符時,可以使用 %v
來表示複數,但當你希望只表示其中的一個部分的時候需要使用 %f
。
複數支持和其它數字類型一樣的運算。當你使用等號 ==
或者不等號 !=
對複數進行比較運算時,注意對精確度的把握。cmath
包中包含了一些操作複數的公共方法。如果你對內存的要求不是特別高,最好使用 complex128 作爲計算類型,因爲相關函數都使用這個類型的參數。