Go 知识点(12) — 类型转换以三方库 cast
類型轉(zhuǎn)換在編程語言中是很常見的操作,在 Go 語言中其類型轉(zhuǎn)換有下面一些注意點(diǎn)。
1. 整數(shù)類型之間的轉(zhuǎn)換
對于整數(shù)類型轉(zhuǎn)換,原則上目標(biāo)類型的取值范圍要包含被轉(zhuǎn)換值,也就是說要轉(zhuǎn)換類型的值取值范圍要小于目標(biāo)類型的取值范圍。
如果相反,即目標(biāo)類型小,而要轉(zhuǎn)換的源值類型大,比如把值的類型從 int16 轉(zhuǎn)換為 int8 ,會出現(xiàn)截斷現(xiàn)象,如下代碼:
func main() {src := int16(-255)dst := int8(src)fmt.Println("dst is ", dst) // dst is 1
}
變量 src 的值是 int16 類型的 -255 ,而變量 dst 的值是由前者轉(zhuǎn)換而來的,類型是 int8 。int16 類型的可表示范圍可比 int8 類型大。
整數(shù)在計算機(jī)中都是以補(bǔ)碼的形式存儲的。其中:
- 正數(shù)補(bǔ)碼和原碼相同;
- 負(fù)數(shù)補(bǔ)碼是原碼各位求反再加 1;
比如,int16 類型的值 -255 的補(bǔ)碼是 1111111100000001 。
該值在轉(zhuǎn)換為 int8 類型的值,那么就會把在較高位置(或者說最左邊位置)上的 8 位二進(jìn)制數(shù)直接截掉,從而得到 00000001 。又由于其最左邊一位是 0 ,表示它是個正整數(shù),以及正整數(shù)的補(bǔ)碼就等于其原碼,所以 dst 的值就是 1 。
規(guī)則:
- 當(dāng)整數(shù)值的類型的有效范圍由寬變窄時,只需在補(bǔ)碼形式下截掉一定數(shù)量的高位二進(jìn)制數(shù)即可;
- 當(dāng)浮點(diǎn)數(shù)類型的值轉(zhuǎn)換為整數(shù)類型值時,會把浮點(diǎn)數(shù)值的小數(shù)部分全部截掉;
2. 整數(shù)轉(zhuǎn)換字符串
把整數(shù)轉(zhuǎn)換為字符串,有兩種方法可以使用,分別是:
- 使用
string直接轉(zhuǎn)換; - 使用
strconv庫方法進(jìn)行轉(zhuǎn)換;
兩者的區(qū)別,可以看下面代碼:
func main() {a := 101s1 := string(a)s2 := strconv.Itoa(a)fmt.Printf("s1 is %#v, type is %T\n", s1, s1)fmt.Printf("s2 is %#v, type is %T\n", s2, s2)
}
輸出結(jié)果:
s1 is "e", type is string
s2 is "101", type is string
我們可以看到區(qū)別,
string方法是將整數(shù)轉(zhuǎn)換為對應(yīng)的ASCII/Unicode碼值;strconv庫的Itoa方法是將整數(shù)轉(zhuǎn)換成整數(shù)字面量對應(yīng)的字符串;
如下代碼也是同樣的
func main() {a := 0x597Ds1 := string(a)s2 := strconv.Itoa(a)fmt.Printf("s1 is %#v, type is %T\n", s1, s1)fmt.Printf("s2 is %#v, type is %T\n", s2, s2)
}
輸出結(jié)果:
s1 is "好", type is string
s2 is "22909", type is string
16 進(jìn)制數(shù) 0x597D 的十進(jìn)制數(shù)字為 22909 ,且其 Unicode 值為漢字的 好 。
但需要關(guān)注的是,被轉(zhuǎn)換的整數(shù)值應(yīng)該可以代表一個有效的 Unicode 代碼點(diǎn),否則轉(zhuǎn)換的結(jié)果將會是 �(僅由高亮的問號組成的字符串值)。
func main() {a := -2s1 := string(a)s2 := strconv.Itoa(a)fmt.Printf("s1 is %#v, type is %T\n", s1, s1)fmt.Printf("s2 is %#v, type is %T\n", s2, s2)
}
輸出結(jié)果為
s1 is "�", type is string
s2 is "-2", type is string
由于 -2 無法代表一個有效的 Unicode 值,所以得到的總會是 � 。
3. string類型與各切片類型之間轉(zhuǎn)換
一個值在從 string 類型向 []byte 類型轉(zhuǎn)換時,除了與 ASCII 編碼兼容的那部分字符集可以用單個字節(jié)表示之外,以 UTF-8 編碼的字符串會被拆分成零散、獨(dú)立的字節(jié),單一字節(jié)是無法代表一個字符的。
func main() {a := "你好"s1 := string(a)s2 := []byte(a)s3 := []rune(a)fmt.Printf("s1 is %#v, type is %T\n", s1, s1)fmt.Printf("s2 is %#v, type is %T\n", s2, s2)fmt.Printf("s3 is %#v, type is %T\n", s3, s3)
}
輸出結(jié)果為:
s1 is "你好", type is string
s2 is []byte{0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd}, type is []uint8
s3 is []int32{20320, 22909}, type is []int32
0xe4, 0xbd, 0xa0 合在一起才能代表字符 你 ,而 0xe5 , 0xa5 , 0xbd 合在一起才能代表符 好。
一個值在從 string 類型向 []rune 類型轉(zhuǎn)換時代表著字符串會被拆分成一個個 Unicode 字符。
[]int32{20320, 22909} // 你好
4. 類型轉(zhuǎn)換三方庫
第三方包 github.com/spf13/cast 專門解決類型轉(zhuǎn)換的問。這個包使用很簡單,主要有兩套函數(shù):
- To_ 形式函數(shù)
這些函數(shù)始終返回所需的類型。如果無法正確轉(zhuǎn)換為對應(yīng)的類型,則返回目標(biāo)類型的零值。
支持的類型包括所有的基本數(shù)據(jù)類型,還支持 time.Time、time.Duration、slice、map 等常用類型。
比如:
cast.ToString("mayonegg") // "mayonegg"
cast.ToString(8) // "8"
cast.ToString(8.31) // "8.31"
cast.ToString([]byte("one time")) // "one time"
cast.ToString(nil) // ""
cast.ToTime("2021-08-10 22:00:00") // 2021-08-10 22:00:00 +0000 UTC
注意,轉(zhuǎn)換為 time.Time 時,需要注意時區(qū)問題。ToTime 默認(rèn)使用 UTC,如果想用其他時區(qū),得類似這么做:
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
fmt.Println(cast.ToTimeInDefaultLocation("2021-08-10 22:00:00", beijing))
當(dāng)然,你也可以這樣:
fmt.Println(cast.ToTimeInDefaultLocation("2021-08-10 22:00:00", time.Local))
不過,Local 表示本地時區(qū),要明確這個本地是不是你想要的。
- To_E 形式函數(shù)
E 表示 error,也就是說,這一系列函數(shù)會返回 error。在無法進(jìn)行類型轉(zhuǎn)換時,會將錯誤原因返回。To_ 形式內(nèi)部調(diào)用的是 To_E 形似,只是它忽略了錯誤。
這種形式就不舉例了。一般地,除非你需要區(qū)分零值是因為出錯導(dǎo)致的還是本身就是零值,否則應(yīng)該使用 To_ 系列函數(shù),畢竟更省事。
總結(jié)
以上是生活随笔為你收集整理的Go 知识点(12) — 类型转换以三方库 cast的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go 知识点(11) — gorouti
- 下一篇: 2022-2028年中国导热硅胶行业市场