仅相同标签不同的相同结构类型之间的不安全转换

时间:2015-10-08 08:13:50

标签: go

考虑两种结构相同但标签不同的类型:

type Foo struct {
  Id int64 `json:"-"`
}

type Bar struct {
  Id int64 `json:"id"`
}

不幸的是,当他们的标签不同并且有充分的理由时,Go的成语禁止在两种类型之间进行投射。但是,我仍然需要能够控制序列化为JSON并且不想使用interface{}类型的数据。

我的问题是,使用golang的unsafe.Pointer在结构相同(但不是标签)的两种类型之间执行强制转换是多么安全?类似的东西:

rf := &Foo{1}
rb := (*Bar)(unsafe.Pointer(rf))

是否有任何机会出现恐慌可能是因为内部两种类型中的数据由于的标签不同而略有不同有关标签的信息与实际类型数据分开,每种类型的数据在结构上是相同的吗?

修改

为了澄清,我应该提一下,尽管上面提供的示例使用了单字段结构,但问题实际上是关于包含多个字段的结构类型。

2 个答案:

答案 0 :(得分:1)

严格说,这不安全。原因是spec的相关部分没有给出结构的内存布局的任何指导。它不保证内存中的字段排序,打包或对齐。从理论上讲,编译器可以根据优化信息确定两个看似相同的结构,根据它们的用法进行不同的表示。这甚至可能是一个Heisenbug,其中违规优化不会在go test版本中发生。

实际上说,这不太可能在任何真正的编译器中发生,你可以安全地进行。对于像您提供的那样的一个场结构尤其如此。在进行此操作之前,您应该确保通过分析来确保复制不充分。

答案 1 :(得分:1)

  

不幸的是,当他们的标签不同且有充分理由时,Go的成语禁止在两种类型之间进行投射

release notes for Go 1.8(目前处于测试阶段)似乎表明此限制现已取消:

  

语言的变化

     

当显式地将值从一种结构类型转换为另一种结构类型时,从Go 1.8开始,标记将被忽略   因此,两个仅在其标签中有所不同的结构可以从一个转换为另一个

func example() {
    type T1 struct {
        X int `json:"foo"`
    }
    type T2 struct {
        X int `json:"bar"`
    }
    var v1 T1
    var v2 T2
    v1 = T1(v2) // now legal
}