Go 語言類型轉換的陷阱
01 介紹
Go 語言作爲強類型語言,在使用 Golang 開發項目時,經常會遇到類型轉換的場景,整型之間可以直接轉換,字節切片和字符串之間也可以直接轉換。
但是,如果整型和字符串之間做類型轉換,則需要使用 strconv
標準庫提供的函數。
02 標準庫 strconv
類型轉換
Go 語言標準庫 strconv[1] 提供了一些類型轉換的函數,比如在項目開發中使用比較多的整型和字符串之間的類型轉換。
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)
}
輸出結果:
int salary=5000
string salaryStr=5000
string age=23
int ageInt=23 err=<nil>
閱讀上面這段代碼,我們使用標準庫 strconv
將整型變量 salary
轉換爲字符串類型變量 salaryStr
;將字符串類型變量 age
轉換爲整型變量 ageInt
。
但是,讀者朋友們有沒有發現一個問題,我們使用標準庫 strconv
提供的函數 Atoi
將字符串類型變量轉換爲整型變量,得到的是 int
類型,如果我們需要得到一個 int8
類型的變量,我們需要繼續做類型轉換,例如:
age := "23"
ageInt, err := strconv.Atoi(age)
ageInt8 := int8(ageInt)
也就是說,如果我們需要將一個字符串類型的變量轉換爲一個非 int
類型的整型變量,需要做二次轉換,在實際項目開發中,使用起來稍微繁瑣一些。
此外,使用標準庫 strconv
做類型轉換,除了在一些場景中稍微繁瑣之外,還有另外一個問題,我們先閱讀以下一段代碼。
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)
}
輸出結果:
string phoneNumber=138001380001380013800013800138000
int phoneNumberInt=9223372036854775807 err=strconv.Atoi: parsing "138001380001380013800013800138000": value out of range
閱讀上面這段代碼輸出的錯誤信息 value out of range
,也就是說如果我們需要轉換的值超出返回,Go 語言標準庫 strconv
提供的函數 Atoi
會返回錯誤。
所以,在使用函數 Atoi
時,我們要做好參數驗證和錯誤處理。
有沒有使用更簡單的類型轉換庫,接下來,我們來看一下流行的三方庫 cast
。
03 三方庫 cast
類型轉換
Go 類型轉換的三方庫 cast
是一個使用比較多的庫,我們使用 cast[2] 來處理 Part02 的類型轉換需求,代碼如下:
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)
}
輸出結果:
string age2=23
int8 age2Int8=23
string phoneNumber2=138001380001380013800013800138000
int phoneNumber2Int=0
閱讀上面這段代碼,我們可以發現,使用 cast
可以直接將字符串類型的變量轉換爲我們需要的整型變量,使用起來不再感到繁瑣。
同時,需要注意的是,如果轉換失敗,將返回類型零值,字符串類型變量 phoneNumber2
在使用 cast
轉換爲 int
類型的變量時,返回的結果就是 int
的類型零值。
使用 cast
比使用 strconv
更簡單,而且不需要處理錯誤。但是,cast
還有一個陷阱,我們需要特別注意一下,我們先閱讀以下一段代碼:
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)
}
輸出結果:
string month=07
int8 monthInt8=7
string month2=08
int8 month2Int8=0
閱讀上面這段代碼的輸出結果,我們可以發現使用 cast
將字符串類型 month
和 month2
轉換爲整型時,字符串是以 "0"
開頭的月份,"07"
轉換後得到整型 7
,而 "08"
轉換後得到整型 0
。
我們再使用 strconv
轉換 "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)
}
輸出結果:
int8 month2Int8=0
int month2Int2=8 err=<nil>
讀者朋友們從輸出結果可以看到,"08"
使用 strconv
轉換後得到整型 8
,所以我們在轉換以一個或多個 "0"
開頭的字符串爲整型時,字符串 "0"
後面的數值大於 7
將不能使用 cast
轉換,最好就是在轉換以一個或多個 "0"
開頭的字符串爲整型時,比如 "08"
、"009"
、"00010"
等,使用 strconv
轉換,而不要使用 cast
轉換。
04 總結
本文我們介紹 Go 語言類型轉換的兩個庫,分別是標準庫 strconv
和三方庫 cast
,其中 cast
更方便、更安全,但是也有陷阱,我們需要特別注意,避免在項目開發中掉進陷阱。
關於這兩個類型轉換庫的更多用法,感興趣的讀者朋友們可以熟讀手冊,多多動手練習。
參考資料
[1] strconv: https://pkg.go.dev/strconv
[2] cast: https://github.com/spf13/cast
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/p1n6EAid5o_knT0i0NWX_Q