go语言接口采用的类型传递方式是值传递。
下面我们通过代码来进行说明(相关代码的基础可以查看go语言接口的定义与实现):
func main() {
var duck Duck duck = yellow.SmallDuck
// 输出duck里面的类型和值
fmt.Printf("%T %v\n", duck, duck)
// 输出duck的foot数目
duck = &True.BigDuck
// 输出duck里面的类型和值
fmt.Printf("%T %v\n", duck, duck) }
代码定义了一个Duck接口,duck接口有两个实现类,一个是SamllDuck,一个是BigDuck,它们各种拥有一个属性foot,其中SamllDuck本身实现了和Duck接口相同的方法,而BigDuck的指针实现了和Duck接口相同的方法,因此在用BigDuck的时候,需要用到它的地址。我们可以通过%T %v 实现输出接口的类型和值。
输出结果如下:
yellow.SmallDuck
foots: 2
*notTrue.BigDuck &
foots: 4
可以看到,第二个duck里面是一个指针类型,而原因是我们传入的是一个实现类的地址。
除了通过printf这种方式,我们还可以通过其它方式获取duck的类型:
func getFoots(duck Duck) {
switch v := duck.(type) {
case yellow.SmallDuck:
fmt.Printf("foots: %d\n", v.Foot)
case *notTrue.BigDuck:
fmt.Printf("foots: %d\n", v.Foot) } }
通过duck.(type)来获得当前函数传入的对象的类型,并且通过匹配输出对应的值。
通过以上两种方式,我们可以知道duck接口里面存在一个实际的类型和实际的值,我们可以通过duck.(yellow.SmallDuck)取出里面的实际值,BigDuck类似,具体信息看代码:
if trueDuck, ok := duck.(yellow.SmallDuck); ok {
fmt.Println(trueDuck.Foot) }
else {
fmt.Println(" this is a fake duck")
}
其中ok是用来判断duck里面的值是否是SamllDuck,避免如果不是SamllDuck而造成程序的中断。
SmallDuck 接口里面是SamllDuck的副本
SmallDuck 接口里面是SamllDuck的副本
BigDuck 接口里面是BigDuck的指针,指向实现者
BigDuck 接口里面是BigDuck的指针,指向实现者
因此我们在操作接口之时,如果需要操作指针,改变传入对象的值的话,不用操作接口的地址,而是将接口里面的实现者的值定义为指针就行(将和接口相同方法的调用者变为指针类型)。
注意:指针类型只能传入指针接收者,值类型可以两者都可以。代码如下:
duck = &yellow.SmallDuck duck = &True.BigDuck
虽然SamllDuck是值类型,但是我们也可以传入指针,这样duck里面的类型也是指针。
interface{}
interface{}表示任何类型,对象.(int)可以将interface类型转为具体的int类型,其它类型的转换类似。
领取专属 10元无门槛券
私享最新 技术干货