不知道大家會不會有跟我一樣的問題,為什麼還要特別介紹型別?鐵人賽都第八天了,我多少也知道有 string (字串)、bool (布林值)、int (數字)等,還有需要特別用一天的鐵人賽來介紹嗎?
答案是:「需要!」,至於為什麼呢?記得我們在鐵人賽第一天介紹 Go 語言時,就有說過他是一種 強型別的語言 , 強型別的語言 就是遇到函式引數型別和實際叫用型別不符合的情況,是會直接 出錯 或者 編譯失敗 的。也因為如此在 Go 語言中型別是很重要的,我們要先搞清楚各個型別,讓正確的型別放在函數引數中,就可以避免不必要的錯誤發生。
接下來就先從數字型別開始介紹起吧!
在 Go 語言中有分兩種數字:
而無論是哪種數字的零值皆為 0 。
而整數內又分為兩種:
其中又根據其內部的儲存容量分為以下幾種型別:
型別 | 解釋 | 範圍 |
---|---|---|
uint8 = (byte) | 無號 8 位元整數 | 0 ~ 255 |
uint16 | 無號 16 位元整數 | 0 ~ 65535 |
uint32 = (rune) | 無號 32 位元整數 | 0 ~ 4294967295 |
uint64 | 無號 64 位元整數 | 0 ~ 18446744073709551615 |
uint | 無號 32 或 64 位元整數 | 0 ~ 4294967295 或 0 ~ 18446744073709551615 |
int8 | 有號 8 位元整數 | -128 ~ 127 |
int16 | 有號 16 位元整數 | -32768 ~ 32767 |
int32 | 有號 32 位元整數 | -2147483648 ~ 2147483647 |
int64 | 有號 64 位元整數 | -9223372036854775808 ~ 9223372036854775807 |
int | 有號 32 或 64 位元整數 | -2147483648 ~ 2147483647 或 -9223372036854775808 ~ 9223372036854775807 |
看到以上有這麼多型別是不是眼花撩亂?(要我全部背起來根本不可能),正常來說我們若要定義變數的型別時,較常使用 int ,但也總會遇到使用 int 有錯誤發生的時候,通常這種錯誤都是因為記憶體耗盡的關係,那只需要確認一下您宣告的變數內的值,若您確定他一定會是 < 255 的正整數,那你只需要將型別改成 uint8 即可以解決記憶體的問題。
在 Go 語言中浮點數也分為兩種
正常來說會優先使用 float64 ,因為精確度較高,同上,若是遇到記憶體空間不足時,才會選用 float32 。
範例 1:
package main
import "fmt"
func main(){
var x int = 1000
var y float32 = 1000
var z float64 = 1000
fmt.Println("int:",x/7) // 整數除整數得整數
fmt.Println("float32",y/7) // 整數除浮點數得浮點數
fmt.Println("float64",z/7)
}
範例 1(執行結果):
int: 142
float32 142.85715
float64 142.85714285714286 // 與前者差別在於精確度
補充:
雖然說 float64 準確度較高,但他並不是完全準確的,因為電腦是用二進位制來儲存小數,故多少還是會有些微誤差的,只是可能他在小數後好幾位,所以並不太影響正常運算功能。但若是重複計算的話,微小的誤差也可能被放大。
範例 2:
package main
import "fmt"
func main(){
var x int = 1000
var y float32 = 1000
var z float64 = 1000
fmt.Println("int:",x/7*7/7*7)
fmt.Println("float32",y/7*7/7*7)
fmt.Println("float64",z/7*7/7*7)
}
範例 2(執行結果):
int: 994
float32 1000
float64 1000
如果今天你很調皮?!硬是宣告一個超過型別範圍的值,則會產生溢位的錯誤。如: uint8 最大就是 255 ,你硬是宣告一個 256 ,那我們來看看會發生什麼事吧^^
範例 3:
package main
import "fmt"
func main(){
var x uint8 = 256 // 硬宣告一個超過型別範圍的值
fmt.Println("uint8:",x)
}
範例 3(執行結果):
cannot use 256 (untyped int constant) as uint8 value in variable declaration (overflows)
這邊錯誤訊息告訴你不能用 256 ,因為在 uint8 已經 overflows 了!
當看到這個錯誤訊息時還好解決,我們只需要確認一下是不是定義一個超出 uint8 範圍的變數,再做修正及可。
溢位還好解決,但當你今天先定義變數後,才賦予一個超過型別範圍的值給他,就不是溢位這麼簡單了,會發生 越界繞回 的問題。如: uint8 最大就是 255 ,你先是宣告一個值為 253 的 uint8 ,然後在後面因為運算等等,將其變數修改為大於 255 的數 ,因為這個變數已經超過最大值,那他便會從最小值開始重新起算,如果用文字敘述有些難理解,直接看範例吧!
範例 4:
package main
import "fmt"
func main(){
var x uint8 = 253
for i := 0; i < 5; i++{
x++ // 每次迴圈 x 的值加一
fmt.Println("uint8:",x) // 超過 255 即從最小值 0 起算
}
}
範例 4(執行結果):
uint8: 254
uint8: 255
uint8: 0
uint8: 1
uint8: 2
因為越界繞回並不會像溢位一樣直接噴錯,所以很多時候發生越界繞回時是很難除錯的,所以當我們在對於變數做運算時,一定要確認一下其型別的最大最小值,以避免發生越界繞回的問題。
如果今天你要宣告一個極大或極小的數,而這個數早已大於或小於 uint64 或 int64 的範圍,可以使用內建套件 math/big,直接使用範例來看看
範例 5:
package main
import (
"fmt"
"math"
"math/big"
)
func main(){
maxInt := math.MaxInt64 // 最大 int 整數
maxInt = maxInt + 1
bigInt := big.NewInt(math.MaxInt64)
bigInt.Add(bigInt,big.NewInt(1))
fmt.Println("原本的maxInt:",math.MaxInt64)
fmt.Println("加1後的maxInt:",maxInt)
fmt.Println("加1後的bigInt:",bigInt)
}
範例 5(執行結果):
原本的maxInt: 9223372036854775807
加1後的maxInt: -9223372036854775808 // 因為原本的 maxInt 已是最大值,加一後發生越界繞回
加1後的bigInt: 9223372036854775808 // 但使用 math/big 內建套件,即可順利加一
不知道大家有沒有跟我一樣的想法:「天阿光是數字怎麼會那麼複雜啦QQ」,但是在搞懂各個數字型別後,才可以讓未來的自己少走冤望路呀,畢竟 Go 是一個強型別的語言,型別錯誤就會報錯的!那我們明天繼續介紹在 Go 語言中的其他核心型別吧~