我是接口新手并试图通过github
进行SOAP请求我不明白
的含义Msg interface{}
在此代码中:
type Envelope struct {
Body `xml:"soap:"`
}
type Body struct {
Msg interface{}
}
我在
中观察到相同的语法fmt.Println
但不了解
取得了什么成就interface{}
答案 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类型的接口值会设置接口值的两个字。
接口值中的第一个单词指向我称之为接口表或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
}
答案 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"
如你所见,它并没有什么神秘之处,但它很容易被滥用。尽可能远离它。
答案 4 :(得分:7)
接口类型指定称为其接口的方法集。一个 接口类型的变量可以使用方法存储任何类型的值 设置是接口的任何超集。据说这种类型 实现界面。未初始化变量的值 接口类型为nil。
类型实现包含其方法的任何子集的任何接口 因此可以实现几个不同的接口。例如, 所有类型都实现空接口:
接口{}
graps的概念是:
T
有3种方法:A
,B
,{{1} }。C
T_interface = (A, B, C)
MyInterface = (A, )
中包含的所有方法都必须包含在MyInterface
您可以推断出所有"界面类型"所有类型都是空接口的超集。
答案 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_interface和https://stackoverflow.com/a/60663003/12817546。
所有类型都实现空接口var _ I = T{}
。参见https://talks.golang.org/2012/goforc.slide#44和https://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。