interface {}的含义是什么?

时间:2014-04-18 06:39:23

标签: go

我是接口新手并试图通过github

进行SOAP请求

我不明白

的含义
Msg interface{}

在此代码中:

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

type Body struct {
    Msg interface{}
}

我在

中观察到相同的语法
fmt.Println

但不了解

取得了什么成就
interface{}

6 个答案:

答案 0 :(得分:166)

您可以参考文章“How to use interfaces in Go”(基于“Russ Cox’s description of interfaces”):

  

接口是什么?

     

界面是两件事:

     
      
  • 这是一套方法,
  •   
  • 但它也是一种类型
  •   
     

interface{} 类型,空接口是没有方法的接口。

     

由于没有implements关键字,所有类型都至少实现零方法,并且自动完成满足接口,所有类型都满足空接口
  这意味着如果您编写一个以interface{}值作为参数的函数,可以为该函数提供任何值

(这就是Msg代表您的问题:任何价值)

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

这里让人感到困惑:

     

DoSomething函数内部,什么是v的类型?

     

初学者通常认为“v属于任何类型”,但这是错误的。
  v不属于任何类型; 属于interface{}类型

     

将值传递到DoSomething函数时,Go运行时将执行类型转换(如有必要),将值转换为interface{}即可。
  所有值在运行时都只有一种类型,而v的一种静态类型是interface{}

     

接口值由两个数据字构成

     
      
  • 一个词用于指向值的基础类型
  • 的方法表   
  • ,另一个词用于指向该值所持有的实际数据。
  •   

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

type Stringer interface {
    String() string
}
  

接口值表示为双字对,给出指向存储在接口中的类型信息的指针和指向相关数据的指针。
  将b分配给Stringer类型的接口值会设置接口值的两个字。

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

  

接口值中的第一个单词指向我称之为接口表或itable (发音为i-table;在运行时源中,C实现名称为Itab)。
  itable从关于所涉及类型的一些元数据开始,然后成为函数指针列表   请注意,itable对应于界面类型,而不是动态类型   就我们的例子而言,Stringer持有类型Binary的itable列出了用于满足Stringer的方法,它只是String:Binary的其他方法(Get)没有出现在{ {1}}。

     

界面值中的第二个单词指向实际数据,在本例中为itable的副本。
  作业b复制var s Stringer = b而不是指向b,原因与b复制相同:如果var c uint64 = b稍后更改,{{{ 1}}和b应该具有原始值,而不是新值   存储在接口中的值可能是任意大的,但只有一个字专用于将值保存在接口结构中,因此赋值在堆上分配一块内存并将指针记录在单字槽中。

答案 1 :(得分:30)

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

示例:

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

答案 2 :(得分:10)

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

示例:

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

这是一个类型实现接口的事实的逻辑扩展,只要它具有接口的所有方法。

答案 3 :(得分:8)

这里已经有了很好的答案。让我也想为直觉理解它的人添加我自己的东西:

接口

以下是使用一种方法的界面:

type Runner interface {
    Run()
}

所以任何具有Run()方法的类型都满足Runner界面:

type Program struct {
    /* fields */
}

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

func (p Program) Stop() {
    /* stopping */
}
  • 虽然Program类型也有一个Stop方法,但它仍然满足Runner接口,因为所需要的只是让接口的所有方法都满足它。

  • 因此,它有一个Run方法,它满足Runner接口。

空接口

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

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

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

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

a = 5
a = 6.5
a = "hello"

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

a = Program{} // ok

interface {}等于上面的Empty接口。

var b interface{}

// true: a == b

b = a
b = 9
b = "bye"

如你所见,它并没有什么神秘之处,但它很容易被滥用。尽可能远离它。

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

答案 4 :(得分:7)

来自Golang Specifications

  

接口类型指定称为其接口的方法集。一个   接口类型的变量可以使用方法存储任何类型的值   设置是接口的任何超集。据说这种类型   实现界面。未初始化变量的值   接口类型为nil。

     

类型实现包含其方法的任何子集的任何接口   因此可以实现几个不同的接口。例如,   所有类型都实现空接口:

     

接口{}

graps的概念是:

  1. 所有内容都有类型。您可以定义一种新类型,让我们称之为T.我们现在说我们的类型T有3种方法:AB,{{1} }。
  2. 为类型指定的方法集称为" 接口类型"。让我们在我们的示例中调用它:T_interface。等于C
  3. 您可以创建"界面类型"通过定义方法的签名T_interface = (A, B, C)
  4. 如果指定类型变量,"接口类型",则只能为其分配具有超集接口的类型你的界面。 这意味着MyInterface = (A, )中包含的所有方法都必须包含在MyInterface
  5. 您可以推断出所有"界面类型"所有类型都是空接口的超集。

答案 5 :(得分:1)

一个示例扩展了@VonC的出色回答以及@ NickCraig-Wood的评论。 import dash import dash_bootstrap_components as dbc external_stylesheets = dbc.themes.BOOTSTRAP app = dash.Dash(__name__, meta_tags=[{"name": "viewport", "content": "width=device-width"}], external_stylesheets=[external_stylesheets], serve_locally=False, prevent_initial_callbacks=True) app.title = "Data" server = app.server app.config['suppress_callback_exceptions'] = True import dash_core_components as dcc import dash_html_components as html from dash.dependencies import Input, Output, State import dash_bootstrap_components as dbc import datetime import dash_table import pandas as pd df = pd.read_csv('query.csv') row1 = html.Div( [dcc.Store(id='local', storage_type='local'), dbc.Row([ dbc.Col([ dbc.Input(id="ad_account_id", type="text", placeholder="Account ID", style={'width': '150px'}, persistence=True, persistence_type='memory'), ])])]) row6 = html.Div([ dbc.Row([ dbc.Col([ dbc.Input(id="get-report", type="text", placeholder="Get Report", style={'width': '150px', 'margin-top': 20, 'margin-left': 10}, persistence=True, persistence_type='memory'), ])])]) row7 = html.Div([ dbc.Row([ dbc.Col([ html.Button(id='submit-button-get', type='submit', children='Submit', style={'width': '150px', 'margin-top': 20, 'margin-left': 10}), ], width={"order": "first"}), dbc.Col([ html.Div(id='output_div-get'), ]) ]) ]) app.layout = dbc.Container(children=[ row1, html.Br(), row6, html.Br(), row7]) @app.callback(Output('output_div-get', 'children'), [Input('submit-button-get', 'n_clicks')], [State('get-report', 'value'), State('ad_account_id', 'value')], ) def f_output(clicks, get_report, ad_account_id): if clicks is not None: new_df = df.loc[df['Report Name'] == get_report] print(new_df) ad_account_id = new_df.iloc[:, 1] print(ad_account_id) return if __name__ == '__main__': app.run_server(debug=True) 可以指向任何东西,您需要强制转换/类型声明才能使用它。

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。从接口类型的值创建方法值是合法的。参见https://golang.org/ref/spec#Interface_types

类型开关确认cat("Fish")的接口类型为i。参见https://golang.org/doc/effective_go.html#type_switch。然后将cat("Fish")重新分配给i。类型开关确认dog("Bone")界面的类型已更改为i

您还可以要求编译器通过尝试分配dog("Bone")来检查类型T是否实现了I接口。参见https://golang.org/doc/faq#guarantee_satisfies_interfacehttps://stackoverflow.com/a/60663003/12817546

所有类型都实现空接口var _ I = T{}。参见https://talks.golang.org/2012/goforc.slide#44https://golang.org/ref/spec#Interface_types。在此示例中,interface{}被重新分配,这一次分配给字符串“ 4.3”。然后i被分配给新的字符串变量i,其中s位于{{1}之前}使用i.(string)转换为float64类型s。最后,将f转换为等于4的int类型的strconv。请参见What is the difference between type conversion and type assertion?

Go的内置映射和切片,以及使用空接口构造容器的能力(带有显式拆箱),这意味着在许多情况下,可以编写出仿制药可以实现的功能(即使不太顺畅)。参见https://golang.org/doc/faq#generics