接口{}是什么意思?

新手上路,请多包涵

我是接口的新手,正在尝试通过 github 进行 SOAP 请求

我不明白的意思

Msg interface{}

在这段代码中:

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

type Body struct {
    Msg interface{}
}

我观察到相同的语法

fmt.Println

但不明白正在取得什么成就

interface{}

原文由 user 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 539
2 个回答

注意:Go 1.18(2022 年第一季度)确实将 interface{} 重命名为 anyinterface{} -d894 的别名)。

请参阅 问题 49884、 CL 368254提交 2580d0e

请参阅此答案的最后一部分。


可以参考《 How to use interfaces in Go 》一文(基于《 Russ Cox对接口的描述》):

什么 接口?

接口是两件事:

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

interface{} 类型(或 any Go 1.18+), 空接口 是没有方法的接口。

由于没有 implements 关键字,所有类型都至少实现零个方法,并且满足接口是自动完成的, 所有类型都满足空接口

这意味着,如果您编写一个将 interface{} 值作为参数的函数, 您可以为该函数提供任何值

(这就是 Msg 在你的问题中所代表的:任何值)

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

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

这是令人困惑的地方:

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

初学者 gophers 被引导相信“ v 是任何类型”,但这是错误的。

v 不是任何类型; 它是 interface{} 类型

将值传递给 DoSomething 函数时,Go 运行时将执行 类型转换(如果需要), 并将该值转换为 interface{}

所有值在运行时都只有一种类型,并且 v 的一种静态类型是 interface{} (或 any 与 Go)。

接口值由两个数据字构成

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

附录:这是 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 )不要出现在 itable 中。

接口值中的第二个字指向实际数据,在本例中是 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 后来的变化, sc 应该有原始值,而不是新值。

存储在接口中的值可能任意大,但只有一个字专门用于保存接口结构中的值,因此赋值在堆上分配一块内存并将指针记录在单字槽中。


问题 33232 似乎指出 any 作为 interface{} 在 Go 1.18(2022 年第一季度)中的别名

Russ Cox 解释说

  1. any ‘ 仅用于约束是一个细节,将出现在泛型的每篇文章中 - 书籍,博客文章等。如果我们认为我们最终可能会允许它,那么从一开始就允许它并避免使所有书面材料无效是有意义的。

  2. any ‘仅用于约束是一种意想不到的删减,它降低了概念的通用性和正交性。说“让我们拭目以待”很容易,但规定用途往往会产生比完全普遍性更多的参差不齐的特征。我们在类型别名中也看到了这一点(谢天谢地,我们拒绝了几乎所有提议的删减)。

  3. 如果“ any ”允许在泛型中使用,但非泛型代码则不允许,那么它可能会鼓励人们过度使用泛型,因为“ any ”比“ interface{} 0cd73afb2027d2a28653f—”更好写 --- ‘,当真正应该通过考虑其他因素来决定是否使用泛型时。

  4. 如果我们也允许’ any ‘用于普通的非泛型用法,那么在代码中看到 interface{} 可以作为一种信号,表明该代码早于泛型并且尚未在后仿制药世界。一些使用 interface{} 代码应该使用泛型。其他代码应该继续使用接口。

以一种或另一种方式重写它以删除文本“ interface{} ”会给人们一种清晰的方式来查看他们更新和没有更新的内容。 (当然,出于向后兼容的原因,一些可能更适合泛型的代码仍必须使用 interface{} ,但它仍然可以更新以确认已考虑并做出决定。)

该线程还包括 关于 interface{} 的解释

这不是特殊的设计,而是 Go 类型声明语法的逻辑结果。

您可以使用具有多个零方法的匿名接口:

 func f(a interface{Foo(); Bar()}) {
   a.Foo()
   a.Bar()
}

类似于如何在任何需要类型的地方使用匿名结构:

 func f(a struct{Foo int; Bar string}) {
   fmt.Println(a.Foo)
   fmt.Println(a.Bar)
}

空接口恰好匹配所有类型,因为所有类型至少有零个方法。

如果您想保持一致/不想引入特殊情况,删除 interface{} 意味着从语言中删除所有接口功能。

原文由 VonC 发布,翻译遵循 CC BY-SA 4.0 许可协议

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
}

去游乐场

原文由 Minty 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题