类型断言

作用:用于提取一个接口底层值。

语法:i.(T), 用来获取混合类型是T的接口的底层值,让我们来看一下例子:

package main

import (  
    "fmt"
)

func assert(i interface{}) {  
    s := i.(int) //get the underlying int value from i
    fmt.Println(s)
}
func main() {  
    var s interface{} = 56
    assert(s)
}

上面的例子中,我们定义了一个空接口类型的变量s,然后给他赋值了整数类型值56,此时,s为混合类型,即空接口类型和整数类型,然后我们可以通过类型断言来获取整数类型的具体值,即56。

正常情况下程序可以正常运行,并且得到我们想要的值,但是如果是下面这种情况的话,结果就不会按照我们预期的来了。还是看一个例子:

package main

import (  
    "fmt"
)

func assert(i interface{}) {  
    s := i.(int) 
    fmt.Println(s)
}
func main() {  
    var s interface{} = "Steven Paul"
    assert(s)
}

上面的例子中,我们给空接口赋值了字符串,因此此时的混合类型是空接口和字符串类型,而我们在这里断言的是整数类型,因此产生一个panic
panic: interface conversion: interface {} is string, not int.
为了解决这个问题,我们可以使用以下语法:

v, ok := i.(T)

如果i的混合类型是T,那么v的值是i的底层值,且ok的值为true

如果i的混合类型不是T,那么v的值是类型T的零值,且ok的值为false, 而且程序不会panic

package main

import (  
    "fmt"
)

func assert(i interface{}) {  
    v, ok := i.(int)
    fmt.Println(v, ok)
}
func main() {  
    var s interface{} = 56
    assert(s)
    var i interface{} = "Steven Paul"
    assert(i)
}

输出结果

56 true  
0 false

类型切换

类型切换用于将接口的具体类型与各种case语句中指定的多种类型进行比较。它类似于switch case。唯一的区别是case指定类型而不是值,而不是常规switch中的情况。

类型切换的语法类似于类型断言。在用于类型断言的语法i.(T)中,应将类型T替换为用于类型切换的关键字type。让我们在下面的程序中查看其工作方式。

package main

import (  
    "fmt"
)

func findType(i interface{}) {  
    switch i.(type) {
    case string:
        fmt.Printf("I am a string and my value is %s\n", i.(string))
    case int:
        fmt.Printf("I am an int and my value is %d\n", i.(int))
    default:
        fmt.Printf("Unknown type\n")
    }
}
func main() {  
    findType("Naveen")
    findType(77)
    findType(89.98)
}

switch后面的表达式的值将会与case从句中指定的类型进行比较,如果匹配,则执行后续的语句。

I am a string and my value is Naveen  
I am an int and my value is 77  
Unknown type

也可以将类型与接口进行比较。如果我们有一个类型,并且该类型实现了一个接口,则可以将该类型与其实现的接口进行比较。

package main

import "fmt"

type Describer interface {  
    Describe()
}
type Person struct {  
    name string
    age  int
}

func (p Person) Describe() {  
    fmt.Printf("%s is %d years old", p.name, p.age)
}

func findType(i interface{}) {  
    switch v := i.(type) {
    case Describer:
        v.Describe()
    default:
        fmt.Printf("unknown type\n")
    }
}

func main() {  
    findType("Naveen")
    p := Person{
        name: "Naveen R",
        age:  25,
    }
    findType(p)
}

在以上的程序中,类型Person实现了接口Describer, 因此当我们传入一个具体的实例时,它会匹配第一个子句,所以会执行后面的语句,而字符串类型并没有实现这个接口,因此默认执行default子句。

输出结果

unknown type  
Naveen R is 25 years old