dpdhnd3577 2016-01-05 18:38
浏览 72
已采纳

如何在Go中为标量派生的类型实现UnmarshalJSON?

I have a simple type that implements conversion of subtyped integer consts to strings and vice versa in Go. I want to be able to automatically unmarshal strings in JSON to values of this type. I can't, because UnmarshalJSON doesn't give me a way to return or modify the scalar value. It's expecting a struct, whose members are set by UnmarshalJSON. The ",string" method doesn't work either for other than builtin scalar types. Is there a way to implement UnmarshalJSON correctly for a derived scalar type?

Here's an example of what I'm after. I want it to print "Hello Ralph" four times, but it prints "Hello Bob" four times because the PersonID isn't being changed.

package main

import (
    "encoding/json"
    "fmt"
)

type PersonID int

const (
    Bob PersonID = iota
    Jane
    Ralph
    Nobody = -1
)

var nameMap = map[string]PersonID{
    "Bob":    Bob,
    "Jane":   Jane,
    "Ralph":  Ralph,
    "Nobody": Nobody,
}

var idMap = map[PersonID]string{
    Bob:    "Bob",
    Jane:   "Jane",
    Ralph:  "Ralph",
    Nobody: "Nobody",
}

func (intValue PersonID) Name() string {
    return idMap[intValue]
}

func Lookup(name string) PersonID {
    return nameMap[name]
}

func (intValue PersonID) UnmarshalJSON(data []byte) error {
    // The following line is not correct
    intValue = Lookup(string(data))
    return nil
}

type MyType struct {
    Person   PersonID `json: "person"`
    Count    int      `json: "count"`
    Greeting string   `json: "greeting"`
}

func main() {
    var m MyType
    if err := json.Unmarshal([]byte(`{"person": "Ralph", "count": 4, "greeting": "Hello"}`), &m); err != nil {
        fmt.Println(err)
    } else {
        for i := 0; i < m.Count; i++ {
            fmt.Println(m.Greeting, m.Person.Name())
        }
    }
}
  • 写回答

2条回答 默认 最新

  • dongyan1841 2016-01-05 18:46
    关注

    Use a pointer receiver for the unmarshal method. If a value receiver is used, changes to the receiver are lost when the method returns.

    The argument to the unmarshal method is JSON text. Unmarshal the JSON text to get a plain string with all JSON quoting removed.

    func (intValue *PersonID) UnmarshalJSON(data []byte) error {
      var s string
      if err := json.Unmarshal(data, &s); err != nil {
        return err
      }
      *intValue = Lookup(s)
      return nil
    }
    

    There's a mismatch between the JSON tags an the example JSON. I changed the JSON to match the tag, but you can change it the other way.

    if err := json.Unmarshal([]byte(`{"person": "Ralph", "count": 4, "greeting": "Hello"}`), &m); err != nil {
    

    <kbd>playground example</kbd>

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 milvus查询出来的score怎么转换成0-1之间的相似性
  • ¥15 多ip服务器站群如何搭建l2tp服务器
  • ¥15 lvgl V9移植到linux开发板
  • ¥15 VB.net中在窗体中创建一个button控件来关闭窗体,但是提示错误,我该怎么办
  • ¥15 网上下载好的程序但是arduinoIDE编程报错,运行不了,哪里出错了,能具体给改一下吗
  • ¥15 Sharepoint JS开发 付费技术指导
  • ¥15 输入程序运行仿真后,烟雾值不实时检测,变成固定值
  • ¥20 数据排序,可选择排序方向
  • ¥15 修改一下代码,考虑进程到达时间不同的情况
  • ¥15 帮我看看这是个啥题,带解题过程和结果,条件如下FCF = 290471.33 g1 = 15% r = 8% g2 = 4% n = 5