如何将一个结构体转换为另一个结构体,但目标结构体拥有更少的字段?

13
我想将一个类型为Big的结构体复制到类型为Small的结构体中,而不需要显式地创建一个与其具有相同字段的新Small结构体。
我已经搜索过其他类似的问题,比如这个这个,但是所有不同结构体类型之间的转换都只针对那些具有相同字段的结构体。
以下是我尝试的示例:
// Big has all the fields that Small has including some new ones.
type Big struct {
    A int
    B string
    C float
    D byte
}

type Small struct {
    A int
    B string
}

// This is the current solution which I hope to not use.
func ConvertFromBigToSmall(big Big) Small {
    return Small{
        A: big.A,
        B: big.B,
    }
}

我原本希望能够做到这样的事情,但它并不起作用:

big := Big{}
small := Small(big)

有没有一种方法可以在不使用Convert函数的情况下转换BigSmall(甚至可能是相反),请问是否存在这样的方法?

4个回答

12

没有内置的支持。如果你真的需要这个功能,你可以编写一个通用函数,使用反射来复制字段。

或者你可以重新设计。如果BigSmall加上一些其他的额外字段,为什么不在Big中重用Small呢?

type Small struct {
    A int
    B string
}

type Big struct {
    S Small
    C float
    D byte
}

如果你有一个名为Big的结构体,那么你也有一个名为Small的结构体:Big.S。如果你有一个Small,需要一个BigBig{S: small}

如果你担心失去短字段名称或不同的编组结果,那么可以使用嵌入而不是命名字段:

type Big struct {
    Small // Embedding
    C float
    D byte
}

那么这些也是合法的:Big.ABig.B。但是如果您需要一个 Small 的值,您可以使用未限定类型名称作为字段名引用嵌入字段,例如 Big.Small(参见Golang 嵌入式结构体类型)。同样地,要从 Small 创建一个 BigBig{Small: small}


1
谢谢您提出不同的方法,这可能是我要采用的方案。 - Yuval Meshorer

2
有没有一种方法可以在不使用“Convert”函数的情况下将“Big”转换为“Small”(甚至反之亦然)?
唯一的选择是手动转换,就像您已经做过的那样。是否将其包装在函数中取决于个人口味/情况。

许多人(包括我自己)认为这是一件好事。任意结构之间的转换具有任意复杂性。拥有某种“快捷”方式来完成它将隐藏该复杂性,这违反了Go不向编码人员隐藏复杂性的核心理念之一。 - Jonathan Hall

2
你可以像这样做:

你可以这样做:

请注意,不要删除HTML标签。
package main

import (
    "fmt"
)

type Big struct {
    Small
    C float32
    D byte
}

type Small struct {
    A int
    B string
}

func main() {
    big := new(Big)
    big.A = 1
    big.B = "test"
    big.C = 2.3
    fmt.Printf("big struct: %+v", big)
    fmt.Println()
    small := big.Small
    fmt.Printf("small struct: %+v", small)
    fmt.Println()
}

output:

big struct: &{Small:{A:1 B:test} C:2.3 D:0}
small struct: {A:1 B:test}

playgroundlink:https://play.golang.org/p/-jP8Wb--att


1
很抱歉,没有直接的方法可以做到这一点。你所做的是正确的方式。
你可以尝试将第一个对象写成JSON格式,然后尝试将其解析为第二个对象。虽然,我不会选择这种方式。
另外一种方式是,大对象将继承小对象。然后你可以进行向下转换。再次强调,我不会这样做,但如果必须的话...

“marshal”和“unmarshal”不会非常低效吗? - Yuval Meshorer
@YuvalMeshorer - 是的,这就是为什么我不建议这样做。 - Roee Gavirel
为什么要提及它? - heisenb0rg
1
@heisenb0rg - 所有选项都值得考虑。也许这是他需要在应用程序初始化时运行一次的东西,因此对他来说,简单的代码比运行时效率更有价值。 - Roee Gavirel
分享不良实践作为解决方案是一种免费的通行证。如果你向某人展示更有效的方法,那么他们可以使用那种方法来初始化数据……无论是一次还是多次。 - heisenb0rg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接