01
介紹
Golang 語言是一門靜态類型的程式設計語言,我們在編寫代碼時,為了提升代碼的靈活性,有時會使用空接口類型,對于空接口類型的變量,一般會通過類型斷言判斷變量的類型,而且可能還會遇到需要類型轉換的場景。本文我們就來介紹一下類型斷言、類型轉換和類型選擇。
02
程式設計技巧
類型斷言
類型斷言提供了通路接口類型值的底層具體值的方式,這裡需要注意的是被類型斷言的值必須是接口類型的值。類型斷言傳回兩個值,被斷言的接口類型值的底層具體值和一個表示是否斷言成功的布爾類型的值。
t, ok := i.(T)
複制
我們在上一篇介紹變量的文章中,介紹過類型推斷,并通過列舉一個示例證明使用類型推斷可以使代碼提升可維護性和健壯性。但是使用類型推斷的代碼也有缺點,我們先看一下這兩段代碼。
未使用類型斷言:
func main () {
id := getVal(1)
// id := getVal("a")
fmt.Println(id)
}
func getVal (val interface{}) interface{} {
return val
}
複制
使用類型斷言:
func main () {
id := getVal(1)
// id := getVal("a")
id, ok := id.(int);
if !ok {
err := errors.New("illegal parameter")
fmt.Println(err)
return
}
fmt.Println(id)
}
func getVal (val interface{}) interface{} {
return val
}
複制
閱讀上面這兩段代碼,main 函數中都是通過調用
getVal()
函數,使用類型推斷的方式給變量 id 指派。不同的是 main 函數,第一段代碼中未使用類型斷言,第二段代碼中使用了類型斷言。是以第一段代碼的 main 函數如果調用
getVal()
函數時傳遞非整型參數,也可以正常輸出;第二段代碼的 main 函數如果調用
getVal()
函數時傳遞非整型參數,将會被斷言代碼攔截。
類型轉換
類型轉換的表達式
T(v)
,将 v 轉換為類型 T。關于類型轉換,我們需要注意的“坑”如下所示:
整型之間的轉換:
func main () {
var a int
a = 128
b := int8(a)
fmt.Println(b) // -128
}
複制
閱讀上面這段代碼,int 類型的變量 a 指派為 128,将變量 a 轉換為 int8 類型的變量 b,輸出變量 b 的結果是 -128,原因是 int 類型和 int8 類型的取值範圍不同。
浮點型轉換為整型:
func main () {
var a float64
a = 3.1415926
b := int(a)
fmt.Println(b) // 3
}
複制
閱讀上面這段代碼,浮點型 float64 的變量 a,轉換為 int 類型的變量 b,輸出結果是 3,變量 a 值的小數部分被截掉了。
整型轉換為字元串類型:
func main () {
var a int
a = -1
b := string(a) // conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
fmt.Println(b) // �
}
複制
閱讀上面這段代碼,int 類型變量 a,轉換為 string 類型變量 b,變量 b 的輸出結果是
�
,表示未知字元,原因是 Unicode 碼點(code point)中沒有 -1。
字元串類型和切片(位元組切片和字元切片)類型互相轉換:
func main () {
var a string
a = "程式設計"
b := []byte(a)
fmt.Println(b) // [231 188 150 231 168 139]
c := []rune(a)
fmt.Println(c) // [32534 31243]
}
複制
閱讀上面這段代碼,将字元串類型的變量 a 分别轉換為位元組切片類型變量 b 和字元切片類型變量 c,它們的輸出結果不同,原因是 UTF-8 編碼一個中文漢字是 3 個位元組, 3 個位元組代表 1 個字元。而字元切片類型的元素本身就是 Unicode 字元。
類型選擇
最後我們再介紹一下類型選擇(type switch),也有人翻譯為類型切換。它是一種按照順序從幾個類型斷言中選擇分支的結構,類型選擇與 switch 語句類似,但是類型選擇中的 case 不是值,而是值的類型。
func main () {
var a interface{}
// a = 1
// a = "golang"
a = false
switch val := a.(type) {
case int:
fmt.Printf("val:%d type:%T\n", val, val)
case string:
fmt.Printf("val:%s type:%T\n", val, val)
default:
fmt.Printf("unknow type:%T\n", val)
}
}
複制
閱讀上面這段代碼,我們使用 type switch 判斷空接口類型變量 a 的實際資料類型是否為我們預定義的類型之一。
03
總結
本文我們介紹了 Golang 語言類型相關的程式設計技巧,通過使用類型斷言、類型轉換和類型選擇,可以使我們的代碼更加靈活。