在Go中为接口分配指针时,会混淆隐式指针解除引用

时间:2015-06-26 05:56:19

标签: pointers go interface

我是Go的新手,我正在研究它的界面功能。

以下是代码:

package main

import (
        "fmt"
        "reflect"
)

type Integer int

func (a Integer) Less(b Integer) bool {
        return a < b
}

func (a *Integer) Add(b Integer) {
        *a += b
}

type LessAdder interface {
        Less(b Integer) bool
        Add(b Integer)
}

var a Integer = 1

var b LessAdder = &a

func main() {
        fmt.Println(reflect.TypeOf(b))
        fmt.Println(b.Less(2))
        b.Add(a)
        fmt.Println(a)

}

它将输出以下内容:

*main.Integer
true
2

嗯,这很好用。

要点是: var b LessAdder = &a的工作原理。指针自动取消引用是在这里发生,还是在b调用成员方法时?

输出*main.Integer告诉我们b是指向Integer类型的指针,因此它是第二种情况。

然后棘手的事情来了: 当我向代码添加fmt.Pringln(*b)时,编译器会出现错误:

 demo/demo1
./demo1.go:31: invalid indirect of b (type LessAdder)

这让我很困惑。 由于bInteger的指针类型,因此取消引用它应该有效。但为什么不呢?

2 个答案:

答案 0 :(得分:7)

你的最后一句:

  

&#34;由于bInteger的指针类型,因此取消引用它应该有效。&#34;

停在那儿。 b 不是指针类型的变量,因此您无法dereference它。

它是interface type的变量,它是一对值和一个类型(值,类型)的示意图,其中&a为值,*Integer为类型(博客)文章The Laws of Reflection,第The representation of an interface部分。)

这是指针类型变量*Integer的声明:

var ip *Integer

这是一种接口类型:

var intf LessAdder

执行此操作时:

var b LessAdder = &a

接口值(类型为LessAdder)是自动/隐式创建的,它将保存值&a(以及类型*Integer)。这是一个有效的操作,因为&a的类型(*Integer)实现了接口LessAdder*Integer的{​​{3}}是接口的超集LessAdder(在这种情况下它们是相同的,接口类型的方法集是它的接口)。

现在当你调用b.Less(2)时,由于Less()有一个值接收器,指针将被取消引用,并且指针值的副本将被制作并使用/传递为方法的值接收器Less()

fmt.Println(reflect.TypeOf(b))并不谎言,但它会打印动态类型的bb的动态类型确实是*Integer,但b静态类型是LessAdder,而静态类型决定了你的能力使用值以及允许的操作符或方法。

答案 1 :(得分:1)

LessAdder被声明为方法LessAdd的接口。由于Add是使用*Integer的接收方声明的,因此*Integer可以是LessAdder; Integer不能。当您执行var b LessAdder = &a时,它是指向a的指针,该指针存储在界面b中。

自动间接发生在调用b.Less(2)时,因为*Integer上的方法和Integer上的方法都对*Integer的方法集有贡献。

您无法使用*b,因为虽然b 包含 *Integer,但其静态类型为LessAdder,而不是*Integer }。撇开接口的表示,LessAdder不是指针类型,*b如果允许的话,根本就没有可表达的类型。

您可以使用type assertion再次访问b Integer *; b.(*Integer)*Integer类型的表达式,*b.(*Integer)Integer。如果b中的值毕竟不是*Integer,则这两种情况都会导致运行时出现混乱。