指向Go中的接口的指针

指向Go中的接口的指针

问题描述:

I'm currently reading the source code of the https://github.com/codegangsta/inject go package to understand how does this package works.

I have some questions concerning the file https://github.com/codegangsta/inject/blob/master/inject.go file thats use some element of the Go language I don't understand and don't find precise explanations in the documentation.

// 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
}

My first question is concerning the for loop. Why does it uses a for loop with a test expression ?

The second relates to the message in the panic function. "A pointer to an interface" is mentioned with the (*MyInterface)(nil). I only encounter a similar construction in the go documentation concerning 'compile time checking structure' when you check that a type implements a structure :

var _ SomeType = (*SomeInterface)(nil)

I did not find any informations about a statement with (*Interface)(nil) and pointer to interface.

How should we interpret this statement ? What is the relation with a pointer to interface and where could I find informations about pointer to interface ?

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

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

  // InterfaceOf取消引用了 指向接口类型的指针。
 //如果value不是指向接口的指针,则发生错误。
 
func InterfaceOf(值interface {})reflect.Type {
t:= reflect.TypeOf(value)
 \  n for t.Kind()== reflect.Ptr {
t = t.Elem()
} 
 
如果t.Kind()!= reflect.Interface {
 panic(“ 一个值 不是指向接口的指针。  (* MyInterface)(nil)“)
} 
 
返回t 
} 
  code>  pre> 
 
 

我的第一个问题与 for 代码>循环。为什么要在测试表达式中使用for循环? p>

第二个与panic函数中的消息相关。(* MyInterface)(nil) code>。当您检查类型是否实现结构时,我只会在go文档中遇到有关“编译时间检查结构”的类似构造: p> var _ SomeType =(* SomeInterface)(nil) code> pre>

我没有找到有关使用(* Interface)的语句的任何信息 (nil) code>和指向接口的指针。 p>

我们应该如何解释该语句?与指向接口的指针有什么关系?在哪里可以找到有关指向接口的指针的信息? p> div>

To summarize both answers:

The for loop

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

t.Elem() is the reflection equivalent to *t, so what this loop does it dereferencing t as long as it holds another pointer value. At the end of the loop, t will hold the value that the last pointer pointed to, not a pointer anymore.

The message

Called [...] with a value that is not a pointer to an interface. (*MyInterface)(nil)

The expression (*MyInterface)(nil) is just an (poorly phrased) example of what is expected as parameter.

The syntax is that of a conversion. A conversion will attempt to convert a value (in this case nil) to a given type (*MyInterface) in this case. So,

(*MyInterface)(nil) 

will give you a zero value of a *MyInterface whose interface type would be MyInterface (play):

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

Of course, this value does not point somewhere meaningful.

Compile time checking of interface implementation

To avoid confusion, the construct you showed

var _ SomeType = (*SomeInterface)(nil)

is probably not what you wanted. I guess you wanted this:

var _ SomeInterface = (*SomeType)(nil)

This construct enables compile time checking of interface implementation for certain types. So in case you're writing a library of some sort and you want to satisfy an interface without using it, you can use this to make sure that your struct implements the interface.

Why this works

First of all, var _ someType is a variable that is going to be checked by the compiler but will not be in the compiled program and is not accessible due to the Blank Identifier _:

The blank identifier may be used like any other identifier in a declaration, but it does not introduce a binding and thus is not declared.

This enables you do declare an arbitrary number of these constructs without interfering with the rest of the program.

You can declare a zero value of a pointer of any type by writing:

(*T)(nil)

Check this example on play.

Next, assignability says that x is assignable to T if T is an interface and x implements T.

So to summarize:

T _ = (*x)(nil)

enforces that x implements T as everything else would be an error.

That for loop is identical to while loop in other languages

The second thing is just a syntax for conversions:

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

Because how this library works you just have to pass the pointer to interface, for loop then dereferences it (if we pass something like (***MyInterface)(nil)) and then if statement checks if the ty[e pointed to is an interface.

The for loop is used to continually dereference the type until it is no longer a pointer. This will handle case where the type acquired an extra indirection(s).
e.g. play.golang.org/p/vR2gKNJChE

As for the (*MyInterface)(nil), pointers to interfaces always1 an error Go code. I assume the author is just describing what he means by pointer to interface with a code snippet since they are so rare.

If you're still intrigued by the forbidden type Russ Cox has some info how exactly all this works under the hood: research.swtch.com/interfaces. You'll have a hard time finding info on the use of pointers to an interface because [1].

(1) OK not really always, but honestly don't do it unless you're a Go pro. In which case don't tell anyone about it.