golang基础(33.接口类型以及转化)
在其他编程语言中,我们可以使用instanceof关键字来判断某个对象是否属于某个类(包括他的父类),而再GO语言中也同样有这样的机制。
接口的断言
package main
import "fmt"
type String1 interface {
func1(s string)
func2(s string)
}
type String2 interface {
func1(s string)
}
type String string
func (s String) func1(str string) {
fmt.Println(str)
}
func (s String) func2(str string) {
}
func main() {
var s String = "test"
var s1 String2 = s
if s2, ok := s1.(String2); ok {
s2.func1("test2")
}
}
上述代码中我们定义了两个接口`String1`和`String2`,其中`String1`作为`String2`的子集。然后定义了一个String类型,实现了这两个接口。在main中我们实例化了一个`String`类型,然后讲其赋值给`String2`接口得到变量`s1`,通过`变量.(类型)`的方式断言变量是否属于`String2`接口。如果是,ok 值为 true,然后执行 if 语句块中的代码;否则 ok 值为 false,不执行 if 语句块中的代码。需要注意的是,类型断言是否成功要在运行期才能够确定,它不像接口赋值,编译器只需要通过静态类型检查即可判断赋值是否可行。
结构体类型断言
结构体类型断言实现语法和接口类型断言一样,基本一致。由于类型断言语法 . 左侧的变量类型必须是接口类型,所以我们需要新增一个接口。
package main
import "fmt"
type IAnimal interface {
Call(s string)
}
type Dog struct {
}
func (d Dog) Call(s string) {
fmt.Println(s)
}
func main() {
dog := Dog{}
var ianimal IAnimal = &dog
if animal, ok := ianimal.(*Dog); ok {
animal.Call("ssss")
}else{
fmt.Println("xxxx")
}
}
如果 ianimal 变量是 Dog 类型,则 ok 值为 true,执行 if 语句块中的代码;否则 ok 值为 false。需要注意的是,在 Go 语言结构体类型断言时,子类的实例并不归属于父类,即使子类和父类属性名和成员方法列表完全一致,因为类与类之间的「继承」是通过组合实现的,并不是 Java/PHP 中的那种父子继承关系,这是新手需要注意的地方。同理,父类实现了某个接口,不代表组合类它的子类也实现了这个接口。比如,我们把上述代码中的 ianimal.(Dog) 替换成 ianimal.(Animal),则查询结果的 ok 值为 false。当然,由于 Dog 实现了 IAnimal 接口,所以接口类型断言 ianimal.(IAnimal) 也会成功,但是如果 Dog 没有实现该接口,则断言失败,即使父类 Animal 实现了这个接口也不行。
基于反射动态断言类型
此外,还可以基于反射在运行时动态进行类型断言,使用 reflect 包提供的 TypeOf 函数即可实现。
fmt.Println(reflect.TypeOf(ianimal))
返回的结果是 animal.Dog。对于基本数据类型,比如 int、string、bool 这些,不必通过反射,直接使用 variable.(type) 表达式即可获取 variable 变量对应的类型值:
package main
import (
"fmt"
"reflect"
)
type IAnimal interface {
Call(s string)
}
type Dog struct {
}
func (d Dog) Call(s string) {
fmt.Println(s)
}
func main() {
dog := Dog{}
var ianimal IAnimal = &dog
if animal, ok := ianimal.(IAnimal); ok {
animal.Call("ssss")
} else {
fmt.Println("xxxx")
}
fmt.Println(reflect.TypeOf(ianimal))
var i interface{} = 1
switch i.(type) {
case int:
fmt.Println("is int")
}
a := i.(int)
fmt.Println(a)
}
其中i.(type)必须在switch中使用。i.(基础类型),用来作为断言变量为某个类型。
func (p *pp) printArg(arg interface{}, verb rune) {
p.arg = arg
p.value = reflect.Value{}
...
// Some types can be done without reflection.
switch f := arg.(type) {
case bool:
p.fmtBool(f, verb)
case float32:
p.fmtFloat(float64(f), 32, verb)
case float64:
p.fmtFloat(f, 64, verb)
case complex64:
p.fmtComplex(complex128(f), 64, verb)
case complex128:
p.fmtComplex(f, 128, verb)
case int:
p.fmtInteger(uint64(f), signed, verb)
case int8:
p.fmtInteger(uint64(f), signed, verb)
case int16:
p.fmtInteger(uint64(f), signed, verb)
case int32:
p.fmtInteger(uint64(f), signed, verb)
case int64:
p.fmtInteger(uint64(f), signed, verb)
case uint:
p.fmtInteger(uint64(f), unsigned, verb)
case uint8:
p.fmtInteger(uint64(f), unsigned, verb)
case uint16:
p.fmtInteger(uint64(f), unsigned, verb)
case uint32:
p.fmtInteger(uint64(f), unsigned, verb)
case uint64:
p.fmtInteger(f, unsigned, verb)
case uintptr:
p.fmtInteger(uint64(f), unsigned, verb)
case string:
p.fmtString(f, verb)
case []byte:
p.fmtBytes(f, verb, "[]byte")
case reflect.Value:
// Handle extractable values with special methods
// since printValue does not handle them at depth 0.
if f.IsValid() && f.CanInterface() {
p.arg = f.Interface()
if p.handleMethods(verb) {
return
}
}
p.printValue(f, verb, 0)
default:
// If the type is not simple, it might have methods.
if !p.handleMethods(verb) {
// Need to use reflection, since the type had no
// interface methods that could be used for formatting.
p.printValue(reflect.ValueOf(f), verb, 0)
}
}
}