指向Go中的接口的指针

时间:2014-01-24 22:36:19

标签: go

我目前正在阅读https://github.com/codegangsta/inject go软件包的源代码,以了解此软件包的工作原理。

我有一些关于文件https://github.com/codegangsta/inject/blob/master/inject.go文件的问题,这些文件使用了我不理解的Go语言的某些元素,并且在文档中找不到精确的解释。

// InterfaceOf dereferences a pointer to an Interface type.
// It panics if value is not an pointer to an interface.

func InterfaceOf(value interface{}) reflect.Type {
        t := reflect.TypeOf(value)

        for t.Kind() == reflect.Ptr {
                t = t.Elem()
        }

        if t.Kind() != reflect.Interface {
                panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
        }

        return t
}

我的第一个问题是关于for循环。为什么它使用带有测试表达式的for循环?

第二个涉及恐慌功能中的消息。 (*MyInterface)(nil)提到了“指向接口的指针”。当你检查一个类型实现一个结构时,我在go文档中只遇到类似'编译时检查结构'的结构:

var _ SomeType = (*SomeInterface)(nil)

我没有找到关于(*Interface)(nil)语句和接口指针的任何信息。

我们应该如何解释这句话?与接口指针的关系是什么,我在哪里可以找到有关接口指针的信息?

3 个答案:

答案 0 :(得分:4)

总结both answers

for循环

for t.Kind() == reflect.Ptr {
    t = t.Elem()
}

t.Elem()是等效于*t的反射,所以只要它保存另一个指针值,这个循环就会解除引用t。在循环结束时,t将保存最后一个指针指向的值,而不是指针。

消息

  

使用不是指向接口的指针的值调用[...]。 (*MyInterface)(nil)

表达式(*MyInterface)(nil)只是表达参数的一个(措辞不当)示例。

语法是conversion的语法。在这种情况下,转换将尝试将值(在这种情况下为nil)转换为给定类型(*MyInterface)。所以,

(*MyInterface)(nil) 

将为您提供*MyInterface的零值,其接口类型为MyInterfaceplay):

x := (*MyInterface)(nil)
InterfaceOf(x) // MyInterface

当然,这个值并没有指向有意义的地方。

编译接口实现的时间检查

为避免混淆,您展示的构造

var _ SomeType =(* SomeInterface)(nil)

可能不是你想要的。我想你想要这个:

var _ SomeInterface = (*SomeType)(nil)

此构造允许对某些类型的接口实现进行编译时检查。 因此,如果您正在编写某种类型的库,并且您希望在不使用的情况下满足接口 使用它,您可以使用它来确保您的结构实现接口。

为什么会这样?

首先,var _ someType是一个将由编译器检查的变量 将不会出现在已编译的程序中,并且由于Blank Identifier _

而无法访问
  

空白标识符可以像声明中的任何其他标识符一样使用,但它不会引入绑定,因此不会声明。

这使您可以声明任意数量的这些结构而不会干扰 其余的计划。

您可以通过写:

来声明任何类型指针的零值
(*T)(nil)

检查this example on play

接下来,assignability表示x如果T是界面而T实施xT可分配给T _ = (*x)(nil)

总结一下:

x

强制T实施{{1}},因为其他一切都是错误。

答案 1 :(得分:0)

for循环与其他语言中的while循环相同

第二件事只是转换的语法:

(*Point)(p)      // p is converted to *Point

因为这个库如何工作你只需要将指针传递给接口,for循环然后取消引用它(如果我们传递类似(*** MyInterface)(nil)的东西)然后if语句检查是否ty [e指向是一个界面。

答案 2 :(得分:0)

for循环用于连续取消引用类型,直到它不再是指针。这将处理类型获得额外间接的情况 例如play.golang.org/p/vR2gKNJChE

至于(*MyInterface)(nil),指向接口的指针总是 1 错误Go代码。我假设作者只是通过指向代码片段的接口来描述他的意思,因为它们非常罕见。

如果你仍然对禁忌类型感兴趣,那么Russ Cox有一些信息如何在引擎盖下完成所有这些工作:research.swtch.com/interfaces。您将很难找到有关使用指针到接口的信息,因为[ 1 ]。

(1)确定并非总是如此,但老实说,除非你是Go专业版,否则不要这样做。在这种情况下,不要告诉任何人。