关于go:interface {}的含义是什么?


What's the meaning of interface{}?

我不熟悉接口,尝试通过Github执行SOAP请求

我不明白

1
Msg interface{}

在此代码中:

1
2
3
4
5
6
7
type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

我在

1
fmt.Println

但不知道通过什么

1
interface{}


您可以参考"如何在Go中使用接口"一文(基于"Russ Cox对接口的描述"):

What is an interface?

An interface is two things:

  • it is a set of methods,
  • but it is also a type

The interface{} type, the empty interface is the interface that has no methods.

Since there is no implements keyword, all types implement at least zero methods, and satisfying an interface is done automatically, all types satisfy the empty interface.
That means that if you write a function that takes an interface{} value as a parameter, you can supply that function with any value.

(这就是Msg在你的问题中所代表的:任何价值)

1
2
3
func DoSomething(v interface{}) {
   // ...
}

Here’s where it gets confusing:

inside of the DoSomething function, what is v's type?

Beginner gophers are led to believe that"v is of any type", but that is wrong.
v is not of any type; it is of interface{} type.

When passing a value into the DoSomething function, the Go runtime will perform a type conversion (if necessary), and convert the value to an interface{} value.
All values have exactly one type at runtime, and v's one static type is interface{}.

An interface value is constructed of two words of data:

  • one word is used to point to a method table for the value’s underlying type,
  • and the other word is used to point to the actual data being held by that value.

附录:这是Russ关于接口结构的文章非常完整:

1
2
3
type Stringer interface {
    String() string
}

Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to the associated data.
Assigning b to an interface value of type Stringer sets both words of the interface value.

http://research.swtch.com/gointer2.png

The first word in the interface value points at what I call an interface table or itable (pronounced i-table; in the runtime sources, the C implementation name is Itab).
The itable begins with some metadata about the types involved and then becomes a list of function pointers.
Note that the itable corresponds to the interface type, not the dynamic type.
In terms of our example, the itable for Stringer holding type Binary lists the methods used to satisfy Stringer, which is just String: Binary's other methods (Get) make no appearance in the itable.

The second word in the interface value points at the actual data, in this case a copy of b.
The assignment var s Stringer = b makes a copy of b rather than point at b for the same reason that var c uint64 = b makes a copy: if b later changes, s and c are supposed to have the original value, not the new one.
Values stored in interfaces might be arbitrarily large, but only one word is dedicated to holding the value in the interface structure, so the assignment allocates a chunk of memory on the heap and records the pointer in the one-word slot.


interface{}表示您可以输入任何类型的值,包括您自己的自定义类型。go中的所有类型都满足空接口(interface{}是空接口)。在您的示例中,msg字段可以具有任何类型的值。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
   "fmt"
)

type Body struct {
    Msg interface{}
}

func main() {
    b := Body{}
    b.Msg ="5"
    fmt.Printf("%#v %T
", b.Msg, b.Msg) // Output:"5" string
    b.Msg = 5

    fmt.Printf("%#v %T", b.Msg, b.Msg) //Output:  5 int
}

去操场


它被称为空接口,由所有类型实现,这意味着您可以在Msg字段中放置任何内容。

例子:

1
2
3
4
5
6
7
8
9
10
11
body := Body{3}
fmt.Printf("%#v
", body) // -> main.Body{Msg:3}

body = Body{"anything"}
fmt.Printf("%#v
", body) // -> main.Body{Msg:"anything"}

body = Body{body}
fmt.Printf("%#v
", body) // -> main.Body{Msg:main.Body{Msg:"anything"}}

这是一个事实的逻辑扩展,即类型一旦拥有接口的所有方法就实现了接口。


这里已经有了很好的答案。让我为那些想要直观理解的人添加我自己的:

接口

这里有一个方法接口:

1
2
3
type Runner interface {
    Run()
}

因此,具有Run()方法的任何类型都满足runner接口:

1
2
3
4
5
6
7
8
9
10
11
type Program struct {
    /* fields */
}

func (p Program) Run() {
    /* running */
}

func (p Program) Stop() {
    /* stopping */
}

  • 尽管程序类型也有一个stop方法,但它仍然满足runner接口,因为需要的只是拥有接口的所有方法来满足它。

  • 所以,它有一个run方法,并且满足runner接口。

  • 小精灵空接口

    下面是一个没有任何方法的命名空接口:

    1
    2
    3
    type Empty interface {
        /* it has no methods */
    }

    所以任何类型都满足这个接口。因为,不需要任何方法来满足这个接口。例如:

    1
    2
    3
    4
    5
    6
    // Because, Empty interface has no methods, following types satisfy the Empty interface
    var a Empty

    a = 5
    a = 6.5
    a ="hello"

    但是,上面的程序类型满足它吗?对:

    1
    a = Program{} // ok

    接口等于上面的空接口。

    1
    2
    3
    4
    5
    6
    7
    var b interface{}

    // true: a == b

    b = a
    b = 9
    b ="bye"

    正如你所看到的,这并没有什么神秘之处,但很容易被滥用。尽量远离它。

    网址:https://play.golang.org/p/a-vwtddwj7g


    根据Golang规范:

    An interface type specifies a method set called its interface. A
    variable of interface type can store a value of any type with a method
    set that is any superset of the interface. Such a type is said to
    implement the interface. The value of an uninitialized variable of
    interface type is nil.

    A type implements any interface comprising any subset of its methods
    and may therefore implement several distinct interfaces. For instance,
    all types implement the empty interface:

    interface{}

    图形的概念是:

  • 一切都有一种类型。你可以定义一个新的类型,我们称之为t,现在我们的类型T有3种方法:ABC
  • 为类型指定的一组方法称为"接口类型"。让我们在示例中调用它:t_接口。等于T_interface = (A, B, C)
  • 您可以通过定义方法的签名来创建"接口类型"。江户十一〔七〕号
  • 当您指定类型为"interface type"的变量时,您只能为其分配具有接口的类型,该接口是您的接口的超集。这意味着MyInterface中包含的所有方法都必须包含在T_interface中。
  • 您可以推断所有类型的所有"接口类型"都是空接口的超集。