在不同类型的结构之间复制公共字段

时间:2018-09-09 18:24:03

标签: go

我有两个结构,其类型如下:

type UserStruct struct {
    UserID      string            `bson:"user_id" json:"user_id"`
    Address     string            `bson:"address" json:"address"`
    Email       string            `bson:"email" json:"email"`
    CreatedAt   time.Time         `bson:"created_at" json:"created_at"`
    PhoneNumber string            `bson:"phone_number" json:"phone_number"`
    PanCard     string            `bson:"pancard" json:"pancard"`
    Details     map[string]string `json:"details"`
}

type SecretsStruct struct {
    UserID      string    `r:"user_id" json:"user_id"`
    Secrets     []string  `r:"secrets" json:secrets`
    Address     string    `r:"address" json:"address"`
    Email       string    `r:"email"json:"email"`
    CreatedAt   time.Time `r:"created_at"json:"created_at"`
    PhoneNumber string    `r:"phone_number" json:"phone_number"`
    PanCard     string    `r:"pancard" json:"pancard"`
}

我已经有一个UserStruct的实例。我想在不使用反射的情况下将两个结构的公共字段从UserStruct复制到SecretStruct的新实例。

1 个答案:

答案 0 :(得分:3)

Go是一种静态类型的语言(不是Python)。如果要在结构之间复制字段,则必须使代码在编译时提供(知道如何执行此操作),或者使用reflect >在运行时执行操作。


请注意,我说的是“导致在编译时提供代码”,因为您不必显式地编写该代码。您可以使用代码生成功能从结构定义中生成复制代码,也可以从生成结构定义和复制代码的更高级定义(例如XML)中生成复制代码。

但是,优秀的Go程序员更喜欢清晰的代码,而不是聪明的解决方案。如果这是一个本地化的要求,那么几乎可以肯定,编写代码生成器来避免“样板”代码是过分的。它的实现将比复制结构的代码花费更长的时间,并且相关的复杂性将带来更多错误的风险。同样,基于reflect的解决方案很复杂,不是明确,仅在需要通用或可扩展解决方案且在编译时无法实现的情况下才推荐使用。

我建议只编写复制代码,并在struct定义和复制方法中添加适当的注释,以确保将来的维护者意识到他们有义务维护复制方法。


示例

// Define your types - bodies elided for brevity

// NOTE TO MAINTAINERS: if editing the fields in these structs, ensure
// the methods defined in source file <filename>.go are updated to
// ensure common fields are copied between structs on instantiation.
type UserStruct struct { ... }
type SecretStruct struct { ... }

// NewSecretStructFromUserStruct populates and returns a SecretStruct
// from the elements common to the two types. This method must be
// updated if the set of fields common to both structs is changed in
// future.
func NewSecretStructFromUserStruct(us *UserStruct) *SecretStruct {
    // You should take care to deep copy where necessary,
    // e.g. for any maps shared between the structs (not
    // currently the case).
    ss := new(SecretStruct)
    ss.UserID = us.UserID
    ss.Address = us.Address
    ss.Email = us.Email
    ss.CreatedAt = us.CreatedAt
    ss.PhoneNumber = us.PhoneNumber
    ss.PanCard = us.PanCard
    return ss
}

// You may also consider this function to be better suited as
// a receiver method on UserStruct.