简体   繁体   English

interface{} 的含义是什么?

[英]What's the meaning of interface{}?

I'm new to interfaces and trying to do SOAP request by github我是接口的新手,并尝试通过github执行 SOAP 请求

I don't understand the meaning of我不明白什么意思

Msg interface{}

in this code:在这段代码中:

type Envelope struct {
    Body `xml:"soap:"`
}

type Body struct {
    Msg interface{}
}

I've observed the same syntax in我观察到相同的语法

fmt.Println

but don't understand what's being achieved by但不明白正在取得什么

interface{}

You can refer to the article " How to use interfaces in Go " (based on " Russ Cox's description of interfaces "):可以参考文章《 How to use interfaces in 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. interface{}类型,空接口就是没有方法的接口。

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 .由于没有implements关键字,所有类型至少实现零个方法,并且自动满足接口,所有类型都满足空接口
That means that if you write a function that takes an interface{} value as a parameter, you can supply that function with any value .这意味着,如果您编写一个将interface{}值作为参数的函数,您可以为该函数提供任何 value

(That is what Msg represents in your question: any value) (这就是Msg在您的问题中代表的含义:任何值)

func DoSomething(v interface{}) {
   // ...
}

Here's where it gets confusing:这是令人困惑的地方:

inside of the DoSomething function, what is v 's type?DoSomething函数内部, v的类型是什么?

Beginner gophers are led to believe that “ v is of any type”, but that is wrong.初学者地鼠被引导相信“ v是任何类型”,但这是错误的。
v is not of any type; v不是任何类型; it is of interface{} type .它是interface{}类型

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 .当将值传递给DoSomething函数时,Go 运行时将执行类型转换(如有必要),并将该值转换为interface{}
All values have exactly one type at runtime, and v 's one static type is interface{} .所有值在运行时都只有一种类型,而v的一种静态类型是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.另一个词用于指向该值所持有的实际数据。

Addendum: This is were Russ's article is quite complete regarding an interface structure:附录:这是 Russ 关于接口结构的非常完整的文章:

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.将 b 分配给 Stringer 类型的接口值会设置接口值的两个字。

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).接口值中的第一个词指向我所说的接口表或 itable (发音为 i-table;在运行时源中,C 实现名称是 Itab)。
The itable begins with some metadata about the types involved and then becomes a list of function pointers. itable 以一些关于所涉及类型的元数据开始,然后成为一个函数指针列表。
Note that the itable corresponds to the interface type, not the dynamic type .请注意, itable 对应于接口类型,而不是动态类型
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 .就我们的示例而言, Stringer持有类型 Binary 的 itable 列出了用于满足 Stringer 的方法,这只是String :Binary 的其他方法 ( Get ) 在itable没有出现。

The second word in the interface value points at the actual data , in this case a copy of b .接口值中的第二个字指向实际数据,在本例中是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.赋值var s Stringer = b复制b而不是指向b的原因与var c uint64 = b复制的原因相同:如果b以后更改,则sc应该具有原始值,而不是新值一。
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{} means you can put value of any type, including your own custom type. interface{}意味着您可以放置​​任何类型的值,包括您自己的自定义类型。 All types in Go satisfy an empty interface ( interface{} is an empty interface). Go 中的所有类型都满足一个空接口( interface{}是一个空接口)。
In your example, Msg field can have value of any type.在您的示例中, Msg 字段可以具有任何类型的值。

Example:例子:

package main

import (
    "fmt"
)

type Body struct {
    Msg interface{}
}

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

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

Go Playground去游乐场

It's called the empty interface and is implemented by all types, which means you can put anything in the Msg field.它被称为空接口,并由所有类型实现,这意味着您可以在Msg字段中放置任何内容。

Example :例子 :

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

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

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

This is the logical extension of the fact that a type implements an interface as soon as it has all methods of the interface.这是一个类型一旦拥有接口的所有方法就实现接口这一事实的逻辑扩展。

There are already good answers here.这里已经有很好的答案了。 Let me add my own too for others who want to understand it intuitively:让我也为其他想要直观理解它的人添加我自己的:


Interface界面

Here's an interface with one method:这是一个带有一种方法的接口:

type Runner interface {
    Run()
}

So any type that has a Run() method satisfies the Runner interface:所以任何有Run()方法的类型都满足 Runner 接口:

type Program struct {
    /* fields */
}

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

func (p Program) Stop() {
    /* stopping */
}
  • Although the Program type has also a Stop method, it still satisfies the Runner interface because all that is needed is to have all of the methods of an interface to satisfy it.虽然 Program 类型也有一个 Stop 方法,但它仍然满足 Runner 接口,因为所需要的只是拥有一个接口的所有方法来满足它。

  • So, it has a Run method and it satisfies the Runner interface.所以,它有一个 Run 方法,它满足 Runner 接口。


Empty Interface空接口

Here's a named empty interface without any methods:这是一个没有任何方法的命名空接口:

type Empty interface {
    /* it has no methods */
}

So any type satisfies this interface.所以任何类型都满足这个接口。 Because, no method is needed to satisfy this interface.因为,不需要任何方法来满足这个接口。 For example:例如:

// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty

a = 5
a = 6.5
a = "hello"

But, does the Program type above satisfy it?但是,上面的程序类型满足它吗? Yes:是的:

a = Program{} // ok

interface{} is equal to the Empty interface above. interface{} 等于上面的 Empty 接口。

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"

As you see, there's nothing mysterious about it but it's very easy to abuse.如您所见,它并没有什么神秘之处,但它很容易被滥用。 Stay away from it as much as you can.尽可能远离它。


https://play.golang.org/p/A-vwTddWJ7G https://play.golang.org/p/A-vwTddWJ7G

From the Golang Specifications :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.接口类型的未初始化变量的值为 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{}界面{}

The concepts to graps are:葡萄的概念是:

  1. Everything has a Type .一切都有一个Type You can define a new type, let's call it T. Let's say now our Type T has 3 methods: A , B , C .你可以定义一个新类型,我们称之为 T。假设现在我们的 Type T有 3 个方法: ABC
  2. The set of methods specified for a type is called the " interface type ".为类型指定的一组方法称为“接口类型”。 Let's call it in our example: T_interface.让我们在我们的例子中称它为:T_interface。 Is equal to T_interface = (A, B, C)等于T_interface = (A, B, C)
  3. You can create an "interface type" by defining the signature of the methods.您可以通过定义方法的签名来创建“接口类型”。 MyInterface = (A, )
  4. When you specify a variable of type , "interface type", you can assign to it only types which have an interface that is a superset of your interface.当您指定类型为“接口类型”的变量时,您只能为其分配具有接口超集的类型。 That means that all the methods contained in MyInterface have to be contained inside T_interface这意味着MyInterface包含的所有方法都必须包含在T_interface

You can deduce that all the "interface types" of all the types are a superset of the empty interface.可以推断出所有类型的所有“接口类型”都是空接口的超集。

An example that extends the excellent answer by @VonC and the comment by @NickCraig-Wood.一个例子扩展了@VonC 的优秀答案和@NickCraig-Wood 的评论。 interface{} can point to anything and you need a cast/type assertion to use it. interface{}可以指向任何东西,您需要一个强制转换/类型断言才能使用它。

package main

import (
    . "fmt"
    "strconv"
)

var c = cat("Fish")
var d = dog("Bone")

func main() {
    var i interface{} = c
    switch i.(type) {
    case cat:
        c.Eat() // Fish
    }

    i = d
    switch i.(type) {
    case dog:
        d.Eat() // Bone
    }

    i = "4.3"
    Printf("%T %v\n", i, i) // string 4.3
    s, _ := i.(string)      // type assertion
    f, _ := strconv.ParseFloat(s, 64)
    n := int(f)             // type conversion
    Printf("%T %v\n", n, n) // int 4
}

type cat string
type dog string
func (c cat) Eat() { Println(c) }
func (d dog) Eat() { Println(d) }

i is a variable of an empty interface with a value cat("Fish") . i是一个空接口的变量,值为cat("Fish") It is legal to create a method value from a value of interface type.从接口类型的值创建方法值是合法的。 See https://golang.org/ref/spec#Interface_types .请参阅https://golang.org/ref/spec#Interface_types

A type switch confirms i interface type is cat("Fish") .类型开关确认i接口类型是cat("Fish") See https://golang.org/doc/effective_go.html#type_switch .请参阅https://golang.org/doc/effective_go.html#type_switch i is then reassigned to dog("Bone") .然后i被重新分配给dog("Bone") A type switch confirms that i interface's type has changed to dog("Bone") .类型开关确认i接口的类型已更改为dog("Bone")

You can also ask the compiler to check that the type T implements the interface I by attempting an assignment: var _ I = T{} .您还可以通过尝试赋值来要求编译器检查类型T实现了接口Ivar _ I = T{} See https://golang.org/doc/faq#guarantee_satisfies_interface and https://stackoverflow.com/a/60663003/12817546 .请参阅https://golang.org/doc/faq#guarantee_satisfies_interfacehttps://stackoverflow.com/a/60663003/12817546

All types implement the empty interface interface{} .所有类型都实现了空接口interface{} See https://talks.golang.org/2012/goforc.slide#44 and https://golang.org/ref/spec#Interface_types .请参阅https://talks.golang.org/2012/goforc.slide#44https://golang.org/ref/spec#Interface_types In this example, i is reassigned, this time to a string "4.3".在这个例子中, i被重新分配,这次是一个字符串“4.3”。 i is then assigned to a new string variable s with i.(string) before s is converted to a float64 type f using strconv .然后将i分配给一个带有i.(string)的新字符串变量s ,然后使用strconvs转换为 float64 类型f Finally f is converted to n an int type equal to 4. See What is the difference between type conversion and type assertion?最后f转换为n一个等于 4 的 int 类型。请参阅类型转换和类型断言有什么区别?

Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly. Go 的内置映射和切片,以及使用空接口构造容器(显式拆箱)的能力意味着在许多情况下,如果不太顺利的话,可以编写执行泛型支持的代码。 See https://golang.org/doc/faq#generics .请参阅https://golang.org/doc/faq#generics

接口是一种类似结构的类型,但不包含任何实现,它是对象和结构类型之间的契约,以满足通用功能或作用于不同类型结构对象的通用功能,例如在下面的代码中 PrintDetails 是一个通用功能以工程师、经理、高级主管的身份处理不同类型的结构,请找到示例代码接口示例https://play.golang.org/p/QnAqEYGiiF7

  • A method can bind to any type (int, string, pointer, and so on) in GO一个方法可以绑定到 GO 中的任何类型(int、string、pointer 等)

  • Interface is a way of declear what method one type should have, as long as A type has implement those methods, this can be assigned to this interface.接口是一种明确一个类型应该有什么方法的方式,只要一个类型实现了这些方法,就可以将this赋值给这个接口。

  • Interface{} just has no declear of method , so it can accept any type Interface{} 只是没有声明 method ,所以它可以接受任何类型

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM