Go -- type 和断言 interface{}转换

Posted ⬆️小马哥⬆️

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go -- type 和断言 interface{}转换相关的知识,希望对你有一定的参考价值。

摘要

类型转换在程序设计中都是不可避免的问题。当然有一些语言将这个过程给模糊了,大多数时候开发者并不需要去关 注这方面的问题。但是golang中的类型匹配是很严格的,不同的类型之间通常需要手动转换,编译器不会代你去做这个事。我之所以说通常需要手动转换,是 因为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

以上是关于Go -- type 和断言 interface{}转换的主要内容,如果未能解决你的问题,请参考以下文章

golang type 和断言 interface{}转换

golang 接口interface{}断言switch type

go语言接口断言

golang类型断言的使用(Type Assertion)

Go语言入门——interface

Go——空接口与断言

(c)2006-2024 SYSTEM All Rights Reserved IT常识