Go -- type 和断言 interface{}转换
Posted ⬆️小马哥⬆️
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go -- type 和断言 interface{}转换相关的知识,希望对你有一定的参考价值。
摘要
类型转换在程序设计中都是不可避免的问题。当然有一些语言将这个过程给模糊了,大多数时候开发者并不需要 去关注这方面的问题。但是golang中的类型匹配是很严格的,不同的类型之间通常需要手动转换,编译器不会代你去做这个事。我之所以说通常需要手动转 换,是因为interface类型作为一个特例,会有不同的处理方式。
golang中的所有类型都有自己的默认值,对此我做了个测试。
$GOPATH/src
----typeassert_test
--------main.go
main.go的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
<code class = "hljs go" ><span class = "hljs-keyword" >package main <span class = "hljs-keyword" >import ( <span class = "hljs-string" > "fmt" ) <span class = "hljs-keyword" >type myStruct <span class = "hljs-keyword" > struct { name <span class = "hljs-typename" > bool userid <span class = "hljs-typename" >int64 } <span class = "hljs-keyword" >var structZero myStruct <span class = "hljs-keyword" >var intZero <span class = "hljs-typename" > int <span class = "hljs-keyword" >var int32Zero <span class = "hljs-typename" >int32 <span class = "hljs-keyword" >var int64Zero <span class = "hljs-typename" >int64 <span class = "hljs-keyword" >var uintZero <span class = "hljs-typename" >uint <span class = "hljs-keyword" >var uint8Zero <span class = "hljs-typename" >uint8 <span class = "hljs-keyword" >var uint32Zero <span class = "hljs-typename" >uint32 <span class = "hljs-keyword" >var uint64Zero <span class = "hljs-typename" >uint64 <span class = "hljs-keyword" >var byteZero <span class = "hljs-typename" >byte <span class = "hljs-keyword" >var boolZero <span class = "hljs-typename" > bool <span class = "hljs-keyword" >var float32Zero <span class = "hljs-typename" >float32 <span class = "hljs-keyword" >var float64Zero <span class = "hljs-typename" >float64 <span class = "hljs-keyword" >var stringZero <span class = "hljs-typename" >string <span class = "hljs-keyword" >var funcZero <span class = "hljs-keyword" >func(<span class = "hljs-typename" > int ) <span class = "hljs-typename" > int <span class = "hljs-keyword" >var byteArrayZero [<span class = "hljs-number" >5]<span class = "hljs-typename" >byte <span class = "hljs-keyword" >var boolArrayZero [<span class = "hljs-number" >5]<span class = "hljs-typename" > bool <span class = "hljs-keyword" >var byteSliceZero []<span class = "hljs-typename" >byte <span class = "hljs-keyword" >var boolSliceZero []<span class = "hljs-typename" > bool <span class = "hljs-keyword" >var mapZero <span class = "hljs-keyword" >map[<span class = "hljs-typename" >string]<span class = "hljs-typename" > bool <span class = "hljs-keyword" >var interfaceZero <span class = "hljs-keyword" >interface{} <span class = "hljs-keyword" >var chanZero <span class = "hljs-keyword" >chan <span class = "hljs-typename" > int <span class = "hljs-keyword" >var pointerZero *<span class = "hljs-typename" > int <span class = "hljs-keyword" >func main() { fmt.Println(<span class = "hljs-string" > "structZero: " , structZero) fmt.Println(<span class = "hljs-string" > "intZero: " , intZero) fmt.Println(<span class = "hljs-string" > "int32Zero: " , int32Zero) fmt.Println(<span class = "hljs-string" > "int64Zero: " , int64Zero) fmt.Println(<span class = "hljs-string" > "uintZero: " , uintZero) fmt.Println(<span class = "hljs-string" > "uint8Zero: " , uint8Zero) fmt.Println(<span class = "hljs-string" > "uint32Zero: " , uint32Zero) fmt.Println(<span class = "hljs-string" > "uint64Zero: " , uint64Zero) fmt.Println(<span class = "hljs-string" > "byteZero: " , byteZero) fmt.Println(<span class = "hljs-string" > "boolZero: " , boolZero) fmt.Println(<span class = "hljs-string" > "float32Zero: " , float32Zero) fmt.Println(<span class = "hljs-string" > "float64Zero: " , float64Zero) fmt.Println(<span class = "hljs-string" > "stringZero: " , stringZero) fmt.Println(<span class = "hljs-string" > "funcZero: " , funcZero) fmt.Println(<span class = "hljs-string" > "funcZero == nil?" , funcZero == <span class = "hljs-constant" >nil) fmt.Println(<span class = "hljs-string" > "byteArrayZero: " , byteArrayZero) fmt.Println(<span class = "hljs-string" > "boolArrayZero: " , boolArrayZero) fmt.Println(<span class = "hljs-string" > "byteSliceZero: " , byteSliceZero) fmt.Println(<span class = "hljs-string" > "byteSliceZero\'s len?" , <span class = "hljs-built_in" >len(byteSliceZero)) fmt.Println(<span class = "hljs-string" > "byteSliceZero\'s cap?" , <span class = "hljs-built_in" >cap(byteSliceZero)) fmt.Println(<span class = "hljs-string" > "byteSliceZero == nil?" , byteSliceZero == <span class = "hljs-constant" >nil) fmt.Println(<span class = "hljs-string" > "boolSliceZero: " , boolSliceZero) fmt.Println(<span class = "hljs-string" > "mapZero: " , mapZero) fmt.Println(<span class = "hljs-string" > "mapZero\'s len?" , <span class = "hljs-built_in" >len(mapZero)) fmt.Println(<span class = "hljs-string" > "mapZero == nil?" , mapZero == <span class = "hljs-constant" >nil) fmt.Println(<span class = "hljs-string" > "interfaceZero: " , interfaceZero) fmt.Println(<span class = "hljs-string" > "interfaceZero == nil?" , interfaceZero == <span class = "hljs-constant" >nil) fmt.Println(<span class = "hljs-string" > "chanZero: " , chanZero) fmt.Println(<span class = "hljs-string" > "chanZero == nil?" , chanZero == <span class = "hljs-constant" >nil) fmt.Println(<span class = "hljs-string" > "pointerZero: " , pointerZero) fmt.Println(<span class = "hljs-string" > "pointerZero == nil?" , pointerZero == <span class = "hljs-constant" >nil) }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> |
1
2
3
|
<code class= "hljs bash" >$ <span class= "hljs-built_in" > cd <span class= "hljs-variable" >$GOPATH /src/typeassert_ <span class= "hljs-built_in" > test $ go build $ . /typeassert_ <span class= "hljs-built_in" > test < /span >< /span >< /span >< /span >< /code > |
您可以清楚的了解到各种类型的默认值。如bool的默认值是false,string的默认值是空串,byte的默认值是0,数组的默认就是这个数 组成员类型的默认值所组成的数组等等。然而您或许会发现在上面的例子中:map、interface、pointer、slice、func、chan的 默认值和nil是相等的。关于nil可以和什么样的类型做相等比较,您只需要知道nil可以赋值给哪些类型变量,那么就可以和哪些类型变量做相等比较。官 方对此有明确的说明:http://pkg.golang.org/pkg/builtin/#Type,也可以看我的另一篇文章:golang: 详解interface和nil。所以现在您应该知道nil只能赋值给指针、channel、func、interface、map或slice类型的变量。如果您用int类型的变量跟nil做相等比较,panic会找上您。
对于字面量的值,编译器会有一个隐式转换。看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
<code class = "hljs go" ><span class = "hljs-keyword" >package main <span class = "hljs-keyword" >import ( <span class = "hljs-string" > "fmt" ) <span class = "hljs-keyword" >func main() { <span class = "hljs-keyword" >var myInt <span class = "hljs-typename" >int32 = <span class = "hljs-number" >5 <span class = "hljs-keyword" >var myFloat <span class = "hljs-typename" >float64 = <span class = "hljs-number" >0 fmt.Println(myInt) fmt.Println(myFloat) }</span></span></span></span></span></span></span></span></span></span></code> |
对于myInt变量,它存储的就是int32类型的5;对于myFloat变量,它存储的是int64类型的0。或许您可能会写出这样的代码,但确实不是必须这么做的:
1
2
3
4
5
6
7
8
9
10
11
12
|
<code class = "hljs go" ><span class = "hljs-keyword" >package main <span class = "hljs-keyword" >import ( <span class = "hljs-string" > "fmt" ) <span class = "hljs-keyword" >func main() { <span class = "hljs-keyword" >var myInt <span class = "hljs-typename" >int32 = <span class = "hljs-typename" >int32(<span class = "hljs-number" >5) <span class = "hljs-keyword" >var myFloat <span class = "hljs-typename" >float64 = <span class = "hljs-typename" >float64(<span class = "hljs-number" >0) fmt.Println(myInt) fmt.Println(myFloat) }</span></span></span></span></span></span></span></span></span></span></span></span></code> |
在C中,大多数类型转换都是可以隐式进行的,比如:
1
2
3
4
5
6
7
8
9
|
<code class = "hljs cpp" ><span class = "hljs-preprocessor" >#<span class = "hljs-keyword" >include <stdio.h> <span class = "hljs-function" ><span class = "hljs-keyword" > int <span class = "hljs-title" >main<span class = "hljs-params" >(<span class = "hljs-keyword" > int argc, <span class = "hljs-keyword" > char **argv) { <span class = "hljs-keyword" > int uid = <span class = "hljs-number" >12345; <span class = "hljs-keyword" > long gid = uid; <span class = "hljs-built_in" > printf (<span class = "hljs-string" > "uid=%d, gid=%d\\n" , uid, gid); <span class = "hljs-keyword" > return <span class = "hljs-number" >0; }</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> |
但是在golang中,您不能这么做。有个类似的例子:
1
2
3
4
5
6
7
8
9
10
11
|
<code class = "hljs puppet" ><span class = "hljs-keyword" >package <span class = "hljs-keyword" >main <span class = "hljs-keyword" >import ( <span class = "hljs-string" > "fmt" ) func <span class = "hljs-keyword" >main() <span class = "hljs-keyword" >{ var <span class = "hljs-literal" >uid int32 = <span class = "hljs-number" >12345 var <span class = "hljs-built_in" >gid int64 = int64(<span class = "hljs-literal" >uid) fmt.<span class = "hljs-constant" >Printf(<span class = "hljs-string" > "uid=%d, gid=%d\\n" , <span class = "hljs-literal" >uid, <span class = "hljs-built_in" >gid) <span class = "hljs-keyword" >}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> |
很显然,将uid赋值给gid之前,需要将uid强制转换成int64类型,否则会panic。golang中的类型区分静态类型和底层类型。您可以用type关键字定义自己的类型,这样做的好处是可以语义化自己的代码,方便理解和阅读。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<code class = "hljs puppet" ><span class = "hljs-keyword" >package <span class = "hljs-keyword" >main <span class = "hljs-keyword" >import ( <span class = "hljs-string" > "fmt" ) <span class = "hljs-built_in" >type <span class = "hljs-constant" >MyInt32 int32 func <span class = "hljs-keyword" >main() <span class = "hljs-keyword" >{ var <span class = "hljs-literal" >uid int32 = <span class = "hljs-number" >12345 var <span class = "hljs-built_in" >gid <span class = "hljs-constant" >MyInt32 = <span class = "hljs-constant" >MyInt32(<span class = "hljs-literal" >uid) fmt.<span class = "hljs-constant" >Printf(<span class = "hljs-string" > "uid=%d, gid=%d\\n" , <span class = "hljs-literal" >uid, <span class = "hljs-built_in" >gid) <span class = "hljs-keyword" >}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code> |
在上面的代码中,定义了一个新的类型MyInt32。对于类型MyInt32来说,MyInt32是它的静态类型,int32是它的底层类型。即使 两个类型的底层类型相同,在相互赋值时还是需要强制类型转换的。可以用reflect包中的Kind方法来获取相应类型的底层类型。
对于类型转换的截断问题,为了问题的简单化,这里只考虑具有相同底层类型之间的类型转换。小类型(这里指存储空间)向大类型转换时,通常都是安全的。下面是一个大类型向小类型转换的示例:
1
2
3
4
5
6
7
8
9
10
11
|
<code class = "hljs puppet" ><span class = "hljs-keyword" >package <span class = "hljs-keyword" >main <span class = "hljs-keyword" >import |