[英]What's the meaning of interface{}?
我是接口的新手,并尝试通过github执行 SOAP 请求
我不明白什么意思
Msg interface{}
在这段代码中:
type Envelope struct {
Body `xml:"soap:"`
}
type Body struct {
Msg interface{}
}
我观察到相同的语法
fmt.Println
但不明白正在取得什么
interface{}
可以参考文章《 How to use interfaces in Go 》(基于《 Russ Cox对接口的描述》):
什么是接口?
接口是两件事:
- 它是一组方法,
- 但它也是一种类型
interface{}
类型,空接口就是没有方法的接口。由于没有implements关键字,所有类型至少实现零个方法,并且自动满足接口,所有类型都满足空接口。
这意味着,如果您编写一个将interface{}
值作为参数的函数,您可以为该函数提供任何 value 。
(这就是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
) 在itable
没有出现。接口值中的第二个字指向实际数据,在本例中是
b
的副本。
赋值var s Stringer = b
复制b
而不是指向b
的原因与var c uint64 = b
复制的原因相同:如果b
以后更改,则s
和c
应该具有原始值,而不是新值一。
存储在接口中的值可能是任意大的,但只有一个字专门用于保存接口结构中的值,因此赋值会在堆上分配一块内存并将指针记录在一个字槽中。
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
}
它被称为空接口,并由所有类型实现,这意味着您可以在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"}}
这是一个类型一旦拥有接口的所有方法就实现接口这一事实的逻辑扩展。
这里已经有很好的答案了。 让我也为其他想要直观理解它的人添加我自己的:
这是一个带有一种方法的接口:
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"
如您所见,它并没有什么神秘之处,但它很容易被滥用。 尽可能远离它。
接口类型指定称为其接口的方法集。 接口类型的变量可以存储任何类型的值,方法集是接口的任何超集。 据说这种类型实现了接口。 接口类型的未初始化变量的值为 nil。
一个类型实现了包含其方法的任何子集的任何接口,因此可以实现几个不同的接口。 例如,所有类型都实现空接口:
界面{}
葡萄的概念是:
T
有 3 个方法: A
, B
, C
。T_interface = (A, B, C)
MyInterface = (A, )
MyInterface
包含的所有方法都必须包含在T_interface
可以推断出所有类型的所有“接口类型”都是空接口的超集。
一个例子扩展了@VonC 的优秀答案和@NickCraig-Wood 的评论。 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
是一个空接口的变量,值为cat("Fish")
。 从接口类型的值创建方法值是合法的。 请参阅https://golang.org/ref/spec#Interface_types 。
类型开关确认i
接口类型是cat("Fish")
。 请参阅https://golang.org/doc/effective_go.html#type_switch 。 然后i
被重新分配给dog("Bone")
。 类型开关确认i
接口的类型已更改为dog("Bone")
。
您还可以通过尝试赋值来要求编译器检查类型T
实现了接口I
: var _ I = T{}
。 请参阅https://golang.org/doc/faq#guarantee_satisfies_interface和https://stackoverflow.com/a/60663003/12817546 。
所有类型都实现了空接口interface{}
。 请参阅https://talks.golang.org/2012/goforc.slide#44和https://golang.org/ref/spec#Interface_types 。 在这个例子中, i
被重新分配,这次是一个字符串“4.3”。 然后将i
分配给一个带有i.(string)
的新字符串变量s
,然后使用strconv
将s
转换为 float64 类型f
。 最后f
转换为n
一个等于 4 的 int 类型。请参阅类型转换和类型断言有什么区别?
Go 的内置映射和切片,以及使用空接口构造容器(显式拆箱)的能力意味着在许多情况下,如果不太顺利的话,可以编写执行泛型支持的代码。 请参阅https://golang.org/doc/faq#generics 。
接口是一种类似结构的类型,但不包含任何实现,它是对象和结构类型之间的契约,以满足通用功能或作用于不同类型结构对象的通用功能,例如在下面的代码中 PrintDetails 是一个通用功能以工程师、经理、高级主管的身份处理不同类型的结构,请找到示例代码接口示例https://play.golang.org/p/QnAqEYGiiF7
一个方法可以绑定到 GO 中的任何类型(int、string、pointer 等)
接口是一种明确一个类型应该有什么方法的方式,只要一个类型实现了这些方法,就可以将this赋值给这个接口。
Interface{} 只是没有声明 method ,所以它可以接受任何类型
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.