Go 語(yǔ)言類型轉(zhuǎn)換的陷阱
01 介紹
Go 語(yǔ)言作為強(qiáng)類型語(yǔ)言,在使用 Golang 開(kāi)發(fā)項(xiàng)目時(shí),經(jīng)常會(huì)遇到類型轉(zhuǎn)換的場(chǎng)景,整型之間可以直接轉(zhuǎn)換,字節(jié)切片和字符串之間也可以直接轉(zhuǎn)換。
但是,如果整型和字符串之間做類型轉(zhuǎn)換,則需要使用 strconv 標(biāo)準(zhǔn)庫(kù)提供的函數(shù)。
02 標(biāo)準(zhǔn)庫(kù) strconv 類型轉(zhuǎn)換
Go 語(yǔ)言標(biāo)準(zhǔn)庫(kù) strconv[1] 提供了一些類型轉(zhuǎn)換的函數(shù),比如在項(xiàng)目開(kāi)發(fā)中使用比較多的整型和字符串之間的類型轉(zhuǎn)換。
func main() {
salary := 5000
salaryStr := strconv.Itoa(salary)
fmt.Printf("%T salary=%d\n", salary, salary)
fmt.Printf("%T salaryStr=%s\n", salaryStr, salaryStr)
age := "23"
ageInt, err := strconv.Atoi(age)
fmt.Printf("%T age=%s\n", age, age)
fmt.Printf("%T ageInt=%d err=%v\n", ageInt, ageInt, err)
}
輸出結(jié)果:
int salary=5000
string salaryStr=5000
string age=23
int ageInt=23 err=<nil>
閱讀上面這段代碼,我們使用標(biāo)準(zhǔn)庫(kù) strconv 將整型變量 salary 轉(zhuǎn)換為字符串類型變量 salaryStr;將字符串類型變量 age 轉(zhuǎn)換為整型變量 ageInt。
但是,讀者朋友們有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題,我們使用標(biāo)準(zhǔn)庫(kù) strconv 提供的函數(shù) Atoi 將字符串類型變量轉(zhuǎn)換為整型變量,得到的是 int 類型,如果我們需要得到一個(gè) int8 類型的變量,我們需要繼續(xù)做類型轉(zhuǎn)換,例如:
age := "23"
ageInt, err := strconv.Atoi(age)
ageInt8 := int8(ageInt)
也就是說(shuō),如果我們需要將一個(gè)字符串類型的變量轉(zhuǎn)換為一個(gè)非 int 類型的整型變量,需要做二次轉(zhuǎn)換,在實(shí)際項(xiàng)目開(kāi)發(fā)中,使用起來(lái)稍微繁瑣一些。
此外,使用標(biāo)準(zhǔn)庫(kù) strconv 做類型轉(zhuǎn)換,除了在一些場(chǎng)景中稍微繁瑣之外,還有另外一個(gè)問(wèn)題,我們先閱讀以下一段代碼。
func main() {
phoneNumber := "138001380001380013800013800138000"
phoneNumberInt, err := strconv.Atoi(phoneNumber)
fmt.Printf("%T phoneNumber=%s\n", phoneNumber, phoneNumber)
fmt.Printf("%T phoneNumberInt=%d err=%v\n", phoneNumberInt, phoneNumberInt, err)
}
輸出結(jié)果:
string phoneNumber=138001380001380013800013800138000
int phoneNumberInt=9223372036854775807 err=strconv.Atoi: parsing "138001380001380013800013800138000": value out of range
閱讀上面這段代碼輸出的錯(cuò)誤信息 value out of range,也就是說(shuō)如果我們需要轉(zhuǎn)換的值超出返回,Go 語(yǔ)言標(biāo)準(zhǔn)庫(kù) strconv 提供的函數(shù) Atoi 會(huì)返回錯(cuò)誤。
所以,在使用函數(shù) Atoi 時(shí),我們要做好參數(shù)驗(yàn)證和錯(cuò)誤處理。
有沒(méi)有使用更簡(jiǎn)單的類型轉(zhuǎn)換庫(kù),接下來(lái),我們來(lái)看一下流行的三方庫(kù) cast。
03 三方庫(kù) cast 類型轉(zhuǎn)換
Go 類型轉(zhuǎn)換的三方庫(kù) cast 是一個(gè)使用比較多的庫(kù),我們使用 cast[2] 來(lái)處理 Part02 的類型轉(zhuǎn)換需求,代碼如下:
func main() {
age2 := "23"
age2Int8 := cast.ToInt8(age2)
fmt.Printf("%T age2=%s\n", age2, age2)
fmt.Printf("%T age2Int8=%d\n", age2Int8, age2Int8)
phoneNumber2 := "138001380001380013800013800138000"
phoneNumber2Int := cast.ToInt(phoneNumber2)
fmt.Printf("%T phoneNumber2=%s\n", phoneNumber2, phoneNumber2)
fmt.Printf("%T phoneNumber2Int=%d\n", phoneNumber2Int, phoneNumber2Int)
}
輸出結(jié)果:
string age2=23
int8 age2Int8=23
string phoneNumber2=138001380001380013800013800138000
int phoneNumber2Int=0
閱讀上面這段代碼,我們可以發(fā)現(xiàn),使用 cast 可以直接將字符串類型的變量轉(zhuǎn)換為我們需要的整型變量,使用起來(lái)不再感到繁瑣。
同時(shí),需要注意的是,如果轉(zhuǎn)換失敗,將返回類型零值,字符串類型變量 phoneNumber2 在使用 cast 轉(zhuǎn)換為 int 類型的變量時(shí),返回的結(jié)果就是 int 的類型零值。
使用 cast 比使用 strconv 更簡(jiǎn)單,而且不需要處理錯(cuò)誤。但是,cast 還有一個(gè)陷阱,我們需要特別注意一下,我們先閱讀以下一段代碼:
func main() {
month := "07"
monthInt8 := cast.ToInt8(month)
fmt.Printf("%T month=%s\n", month, month)
fmt.Printf("%T monthInt8=%d\n", monthInt8, monthInt8)
month2 := "08"
month2Int8 := cast.ToInt8(month2)
fmt.Printf("%T month2=%s\n", month2, month2)
fmt.Printf("%T month2Int8=%d\n", month2Int8, month2Int8)
}
輸出結(jié)果:
string month=07
int8 monthInt8=7
string month2=08
int8 month2Int8=0
閱讀上面這段代碼的輸出結(jié)果,我們可以發(fā)現(xiàn)使用 cast 將字符串類型 month 和 month2 轉(zhuǎn)換為整型時(shí),字符串是以 "0" 開(kāi)頭的月份,"07" 轉(zhuǎn)換后得到整型 7,而 "08" 轉(zhuǎn)換后得到整型 0。
我們?cè)偈褂?nbsp;strconv 轉(zhuǎn)換 "08",代碼如下:
func main() {
month2 := "08"
month2Int8 := cast.ToInt8(month2)
fmt.Printf("%T month2=%s\n", month2, month2)
fmt.Printf("%T month2Int8=%d\n", month2Int8, month2Int8)
month2Int2, err := strconv.Atoi(month2)
fmt.Printf("%T month2Int2=%d err=%v\n", month2Int2, month2Int2, err)
}
輸出結(jié)果:
int8 month2Int8=0
int month2Int2=8 err=<nil>
讀者朋友們從輸出結(jié)果可以看到,"08" 使用 strconv 轉(zhuǎn)換后得到整型 8,所以我們?cè)谵D(zhuǎn)換以一個(gè)或多個(gè) "0" 開(kāi)頭的字符串為整型時(shí),字符串 "0" 后面的數(shù)值大于 7 將不能使用 cast 轉(zhuǎn)換,最好就是在轉(zhuǎn)換以一個(gè)或多個(gè) "0" 開(kāi)頭的字符串為整型時(shí),比如 "08"、"009"、"00010" 等,使用 strconv 轉(zhuǎn)換,而不要使用 cast 轉(zhuǎn)換。
04 總結(jié)
本文我們介紹 Go 語(yǔ)言類型轉(zhuǎn)換的兩個(gè)庫(kù),分別是標(biāo)準(zhǔn)庫(kù) strconv 和三方庫(kù) cast,其中 cast 更方便、更安全,但是也有陷阱,我們需要特別注意,避免在項(xiàng)目開(kāi)發(fā)中掉進(jìn)陷阱。