在不使用临时结构的情况下实施Unmarshaller

时间:2018-08-11 18:16:52

标签: json go stack-overflow unmarshalling

下面有一个Unmarshaller实现,因为time.Unix仅接受秒或纳秒,但我的数据源以毫秒为单位。在问我问题之前,这里是一些代码

代码:

type Platform struct {
    Status                CampaignStatus `json:"status" bson:"status"`
    TotalBudget           int            `json:"total_budget" bson:"totalBudget"`
    RemainingBudget       int            `json:"remaining_budget" bson:"remainingBudget"`
    MillisecondsStartDate int64          `json:"start_date"`
    StartDate             time.Time      `bson:"startDate"`
    MillisecondsEndDate   int64          `json:"end_date"`
    EndDate               time.Time      `bson:"endDate"`
    Audiance              Audiance       `json:"target_audiance" bson:"targetAudiance"` //typo?
    Creatives             Creatives      `json:"creatives" bson:"Creatives"`
    Insights              Insights       `json:"insights" bson:"insights"`
}

func (p *Platform) UnmarshalJSON(b []byte) (err error) {

    p2 := struct {
        Status                CampaignStatus `json:"status" bson:"status"`
        TotalBudget           int            `json:"total_budget" bson:"totalBudget"`
        RemainingBudget       int            `json:"remaining_budget" bson:"remainingBudget"`
        MillisecondsStartDate int64          `json:"start_date"`
        StartDate             time.Time      `bson:"startDate"`
        MillisecondsEndDate   int64          `json:"end_date"`
        EndDate               time.Time      `bson:"endDate"`
        Audiance              Audiance       `json:"target_audiance" bson:"targetAudiance"` //typo?
        Creatives             Creatives      `json:"creatives" bson:"Creatives"`
        Insights              Insights       `json:"insights" bson:"insights"`
    }{}

    err = json.Unmarshal(b, &p2)
    if err != nil {
        return
    }

    p2.StartDate = time.Unix(0, p2.MillisecondsStartDate*int64(time.Millisecond/time.Nanosecond))
    p2.EndDate = time.Unix(0, p2.MillisecondsEndDate*int64(time.Nanosecond/time.Microsecond))

    *p = p2

    return
}

我的问题是

  1. 在这种情况下,有没有一种方法可以在不创建中间结构的情况下实现Unmarshaller?如您所见,如果我使用中间结构的Platform类型nottead,则会出现堆栈溢出错误。
  2. 这种方法会导致内存泄漏吗?

2 个答案:

答案 0 :(得分:1)

您可以在Platform结构内构成编组可以作为匿名结构处理的字段,例如:

type platformInner struct {
    Status                CampaignStatus `json:"status" bson:"status"`
    TotalBudget           int            `json:"total_budget" bson:"totalBudget"`
    RemainingBudget       int            `json:"remaining_budget" bson:"remainingBudget"`
    MillisecondsStartDate int64          `json:"start_date"`

    MillisecondsEndDate   int64          `json:"end_date"`

    Audiance              Audiance       `json:"target_audiance" bson:"targetAudiance"` //typo?
    Creatives             Creatives      `json:"creatives" bson:"Creatives"`
    Insights              Insights       `json:"insights" bson:"insights"`
}

type Platform struct {
    platformInner
    StartDate             time.Time      `bson:"startDate"`
    EndDate               time.Time      `bson:"endDate"`
}

然后在自定义解组器中解组到嵌套结构中,并设置其他值。

func (p *Platform) UnmarshalJSON(b []byte) (err error) {
    var inner platformInner
    err = json.Unmarshal(b, &inner)
    if err != nil {
        return
    }

    tmp := &Platform{
        innerPlatform: inner,
        StartDate:     time.Unix(0, inner.MillisecondsStartDate*int64(time.Millisecond/time.Nanosecond))
        EndDate:       time.Unix(0, inner.MillisecondsEndDate*int64(time.Nanosecond/time.Microsecond))
    }

    *p = tmp

    return
}

答案 1 :(得分:1)

您无需为匿名“ p2”结构类型复制结构定义,而可以使用新名称(例如“ PlatformTemp”)为它命名别名,

func (p *Platform) UnmarshalJSON(b []byte) (err error) {
  type PlatformTemp Platform
  var p2 PlatformTemp

  err = json.Unmarshal(b, &p2)
  // ...

  *p = Platform(p2)
  return nil
}

由于类型“ Platform”和“ PlatformTemp”具有相同的字段,因此可以通过简单的强制转换将它们彼此分配;但是,由于“ PlatformTemp”没有定义“ UnmarshalJSON”方法,因此它将使用默认的拆组器。