我是接口的新手,并试图通过github做SOAP请求
我不明白的意思
Msg interface{}
Run Code Online (Sandbox Code Playgroud)
在这段代码中:
type Envelope struct {
Body `xml:"soap:"`
}
type Body struct {
Msg interface{}
}
Run Code Online (Sandbox Code Playgroud)
我观察到相同的语法
fmt.Println
Run Code Online (Sandbox Code Playgroud)
但不明白所取得的成就
interface{}
Run Code Online (Sandbox Code Playgroud)
Von*_*onC 180
您可以参考文章" 如何在Go中使用接口 "(基于" Russ Cox的接口描述 "):
什么是界面?
界面是两件事:
- 这是一套方法,
- 但它也是一种类型
该
interface{}
类型的空接口是没有方法的接口.由于没有implements关键字,所有类型都实现至少零方法,并且自动完成满足接口,所有类型都满足空接口.
这意味着如果您编写一个将interface{}
值作为参数的函数,则可以为该函数提供任何值.
(这就是Msg
你的问题所代表的:任何价值)
func DoSomething(v interface{}) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
这是令人困惑的地方:
在
DoSomething
函数内部,什么是v
类型?初学者被认为是"
v
任何类型",但这是错误的.
v
不属于任何类型; 它是interface{}
类型的.将值传递给
DoSomething
函数时,Go运行时将执行类型转换(如果需要),并将值转换为interface{}
值.
所有值在运行时都只有一种类型,而v
一种静态类型是interface{}
.接口值由两个数据字构成:
- 一个单词用于指向值的基础类型的方法表,
- 另一个词用于指向该值所持有的实际数据.
附录:这是Russ的文章在界面结构方面相当完整:
type Stringer interface {
String() string
}
Run Code Online (Sandbox Code Playgroud)
接口值表示为双字对,给出指向存储在接口中的类型的信息的指针和指向相关数据的指针.
将b分配给Stringer类型的接口值会设置接口值的两个字.
接口值中的第一个单词指向我称之为接口表或itable(发音为i-table;在运行时源中,C实现名称为Itab).
itable从关于所涉及类型的一些元数据开始,然后成为函数指针的列表.
请注意,itable对应于接口类型,而不是动态类型.
就我们的例子而言,Stringer
持有类型Binary 的itable 列出了用于满足Stringer的方法,它只是String
:Binary的其他方法(Get
)没有出现在itable
.接口值中的第二个字指向实际数据,在这种情况下是一个副本
b
.
由于var s Stringer = b
制作副本的原因相同,分配会复制b
而不是指向:如果稍后更改,并且应该具有原始值,而不是新值. 存储在接口中的值可能是任意大的,但只有一个字专用于将值保存在接口结构中,因此赋值在堆上分配一块内存并将指针记录在单字槽中.b
var c uint64 = b
b
s
c
Min*_*nty 32
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
}
Run Code Online (Sandbox Code Playgroud)
Den*_*ret 11
它被称为空接口,由所有类型实现,这意味着您可以在该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"}}
Run Code Online (Sandbox Code Playgroud)
这是一个类型实现接口的事实的逻辑扩展,只要它具有接口的所有方法.
Ina*_*mus 10
这里已经有了很好的答案.让我自己也加入我想要直观理解它的人:
这是一个有一个方法的接口:
type Runner interface {
Run()
}
Run Code Online (Sandbox Code Playgroud)
因此任何具有Run()
方法的类型都满足Runner接口:
type Program struct {
/* fields */
}
func (p Program) Run() {
/* running */
}
func (p Program) Stop() {
/* stopping */
}
Run Code Online (Sandbox Code Playgroud)
虽然Program类型也有一个Stop方法,但它仍然满足Runner接口,因为所需要的只是让接口的所有方法都满足它.
因此,它有一个Run方法,它满足Runner接口.
这是一个没有任何方法的命名空接口:
type Empty interface {
/* it has no methods */
}
Run Code Online (Sandbox Code Playgroud)
所以任何类型都满足这个接口.因为,不需要任何方法来满足此接口.例如:
// Because, Empty interface has no methods, following types satisfy the Empty interface
var a Empty
a = 5
a = 6.5
a = "hello"
Run Code Online (Sandbox Code Playgroud)
但是,上面的程序类型是否满足它?是:
a = Program{} // ok
Run Code Online (Sandbox Code Playgroud)
interface {}等于上面的Empty接口.
var b interface{}
// true: a == b
b = a
b = 9
b = "bye"
Run Code Online (Sandbox Code Playgroud)
如你所见,它并没有什么神秘之处,但它很容易被滥用.尽可能远离它.
https://play.golang.org/p/A-vwTddWJ7G
来自Golang规格:
接口类型指定称为其接口的方法集.接口类型的变量可以使用方法集存储任何类型的值,该方法集是接口的任何超集.据说这种类型实现了接口.接口类型的未初始化变量的值为nil.
类型实现包括其方法的任何子集的任何接口,因此可以实现若干不同的接口.例如,所有类型都实现空接口:
接口{}
graps的概念是:
T
有3种方法:A
,B
,C
.T_interface = (A, B, C)
MyInterface = (A, )
MyInterface
包含在内的所有方法都必须包含在内部T_interface
您可以推断出所有类型的所有"接口类型"都是空接口的超集.