【问题标题】:Golang struct assignability and type identityGolang 结构可分配性和类型标识
【发布时间】:2021-09-06 16:15:45
【问题描述】:

我有以下 2 个结构:

    func main() {
        type A struct {
            v int
        }
        type B struct {
            v int
        }
        var b B = A{}
    }

分配var b B = A{} 失败并显示错误消息:

不能使用 'A{}'(类型 A)作为类型 B

但在golang spec:Type identity 中它说:

如果两个结构类型具有相同的字段序列,并且相应的字段具有相同的名称、相同的类型和相同的标签,则它们是相同的。来自不同包的非导出字段名称总是不同的。

所以,我希望 AB 类型相同。在spec:Assignability 中写道:

如果以下条件之一适用,则值 x 可分配给 T 类型的变量(“x 可分配给 T”):

  • x 的类型与 T 相同。

鉴于所有这些信息,我倾向于认为分配应该成功,因为 A{} 的类型与 B 相同,但显然我遗漏了一些东西。

那么,我在这里缺少什么来了解错误消息的根本原因?

【问题讨论】:

    标签: go struct types


    【解决方案1】:

    请注意,您指向的定义以:

    开头
    A defined type is always different from any other type.
    

    AB 是定义类型,它们的名称不同,所以它们是不同的。 struct { v int } 类型与任何类型 struct {v int} 相同,但在这种情况下,这些不是定义的类型。例如,您可以声明:

    func f(x struct {v int})
    

    然后你可以调用:

    f(struct {v int}{v:1})
    

    这两个结构是相等的。

    您仍然可以使用以下方法分配 AB

    var b B = B(A{})
    

    这是因为AB 的底层类型在结构上是相同的。

    【讨论】:

      【解决方案2】:

      所以给定类型AB 定义为:

          type A struct {
              v int
          }
      
          type B struct {
              v int
          }
      

      类型是否相同?

      没有。来自Type Definitions

      类型定义创建具有相同基础类型的新的不同类型

      什么是 A 和 B 基础类型?

      两者都是struct { v int }。来自

      如果T 是预先声明的布尔、数字或字符串类型之一,或类型文字,则对应的基础类型是 T 本身。

      因此,鉴于类型声明的格式为 TypeSpec = AliasDecl | TypeDef .TypeDef = identifier Type .,您可以对类型进行模式匹配,并查看 AB 都符合以下类型定义:

      • AB标识符
      • struct { v int } 是它们的底层结构类型文字

      分配如何运作?

      Assignability 你可以看到没有条件适用:

      • x 的类型与 T 相同。AB 不相同,因为它们是不同的定义类型
      • x 的类型 V 和 T 具有相同的底层类型,并且 V 或 T 中至少有一个不是已定义类型。 — 都是已定义类型

      所以A 类型的变量不能分配给B 类型的变量,反之亦然。不可赋值性也意味着你不能将A 类型的变量传递给Bbecause 类型的函数参数:

      参数必须是可分配给F的参数类型的单值表达式

      Burak 回答 func foo(x struct{ v int }) 的示例可以编译,因为 foo 的参数类型是结构文字,而不是定义的类型,并且属于可分配性条件。

      转化是如何进行的?

      您可以从A 转换为B,因为从Conversion`

      在以下任何一种情况下,非常量值 x 都可以转换为类型 T:

      • [...]
      • 忽略结构标签(见下文),x 的类型和 T 具有相同的底层类型

      我们在上面证明了两个结构确实具有相同的底层类型。因此编译:

      var a A = A(B{})


      游乐场:https://play.golang.org/p/UyEYrbUufA5

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-24
        • 2017-12-24
        • 1970-01-01
        • 2021-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多