当前位置: 移动技术网 > IT编程>脚本编程>Go语言 > Go基础系列:接口类型探测和type-switch

Go基础系列:接口类型探测和type-switch

2018年11月02日  | 移动技术网IT编程  | 我要评论
接口类型探测:类型断言 接口实例中存储了实现接口的类型实例,类型的实例有两种:值类型实例和指针类型实例。在程序运行过程中,接口实例存储的实例类型可能会动态改变。例如: 所以,需要一种探测接口实例所存储的是值类型还是指针类型。 探测的方法是: 和`ins.( Type)`。它们有两个返回值,第二个返回 ...

接口类型探测:类型断言

接口实例中存储了实现接口的类型实例,类型的实例有两种:值类型实例和指针类型实例。在程序运行过程中,接口实例存储的实例类型可能会动态改变。例如:

// ins是接口实例
var ins shaper

// ins存储值类型的实例
ins = c1

// 一段时间后...
...

// ins存储指针类型的实例,存储的类型发生改变
ins = c2

// 一段时间后...

// ins可能存储另一个类型实例
ins = s1

所以,需要一种探测接口实例所存储的是值类型还是指针类型。

探测的方法是:ins.(type)ins.(*type)。它们有两个返回值,第二个返回值是ok返回值,布尔类型,第一个返回值是探测出的类型。也可以只有一个返回值:探测出的类型。

// 如果ins保存的是值类型的type,则输出
if t, ok := ins.(type); ok {
    fmt.printf("%t\n", v)
}

// 如果ins保存的是指针类型的*type,则输出
if t, ok := ins.(*type); ok {
    fmt.printf("%t\n", v)
}

// 一个返回值的探测
t := ins.(type)
t := ins.(*type)

以下是一个例子:

package main

import "fmt"

// shaper 接口类型
type shaper interface {
    area() float64
}

// square struct类型
type square struct {
    length float64
}

// square类型实现shaper中的方法area()
func (s square) area() float64 {
    return s.length * s.length
}

func main() {
    var ins1, ins2, shaper

    // 指针类型的实例
    s1 := new(square)
    s1.length = 3.0
    ins1 = s1
    if v, ok := ins1.(*square); ok {
        fmt.printf("ins1: %t\n", v)
    }

    // 值类型的实例
    s2 := square{4.0}
    ins2 = s2
    if v, ok := ins2.(square); ok {
        fmt.printf("ins2: %t\n", v)
    }
}

上面两个printf都会输出,因为它们的类型判断都返回true。如果将ins2.(square)改为ins2.(*square),第二个printf将不会输出,因为ins2它保存的是值类型的实例。

特别需要注意的是,ins必须明确是接口实例。例如,以下前两种声明是有效的,第三种推断类型是错误的,因为它可能是接口实例,也可能是类型的实例副本。

var ins shaper     // 正确
ins := shaper(s1)  // 正确
ins := s1          // 错误

当ins不能确定是接口实例时,用它来进行测试,例如ins.(square)将会报错:

invalid type assertion:ins.(square) (non-interface type (type of ins) on left)

它说明了左边的ins是非接口类型(non-interface type)。

type switch结构

switch流程控制结构还可以用来探测接口实例保存的类型。这种结构称为type-switch

用法如下:

switch v := ins.(type) {
case *square:
    fmt.printf("type square %t\n", v)
case *circle:
    fmt.printf("type circle %t\n", v)
case nil:
    fmt.println("nil value: nothing to check?")
default:
    fmt.printf("unexpected type %t", v)
}

其中ins.(type)中的小写type是固定的词语。

以下是一个使用示例:

package main

import (
    "fmt"
)

// shaper 接口类型
type shaper interface {
    area() float64
}

// circle struct类型
type circle struct {
    radius float64
}

// circle类型实现shaper中的方法area()
func (c *circle) area() float64 {
    return 3.14 * c.radius * c.radius
}

// square struct类型
type square struct {
    length float64
}

// square类型实现shaper中的方法area()
func (s square) area() float64 {
    return s.length * s.length
}

func main() {
    s1 := &square{3.3}
    whichtype(s1)

    s2 := square{3.4}
    whichtype(s2)

    c1 := new(circle)
    c1.radius = 2.3
    whichtype(c1)
}

func whichtype(n shaper) {
    switch v := n.(type) {
    case *square:
        fmt.printf("type square %t\n", v)
    case square:
        fmt.printf("type square %t\n", v)
    case *circle:
        fmt.printf("type circle %t\n", v)
    case nil:
        fmt.println("nil value: nothing to check?")
    default:
        fmt.printf("unexpected type %t", v)
    }
}

上面的type-switch中,之所以没有加上case circle,是因为circle只实现了指针类型的receiver,根据method set对接口的实现规则,只有指针类型的circle示例才算是实现了接口shaper,所以将值类型的示例case circle放进type-switch是错误的。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网