(评论)
(comments)

原始链接: https://news.ycombinator.com/item?id=43376769

Hacker News 的一个帖子讨论了在 Go 中解码 JSON 联合类型的问题,这是一个常见难题。原文讨论了如何在不发生恐慌的情况下处理可能格式错误的 JSON 结构。 几位评论者强调了将字段区分的 JSON 对象映射到 Go 接口的挑战。一位评论者认为错误是由于契约问题和用户错误造成的。其他人提出了解决方案,例如使用 `gjson` 来提取类型字段以更快地确定对象类型,以及一个名为 `pjson` 的自定义库。 有人提议改进 `encoding/json/v2` 包,允许自定义 Unmarshaler,但真正的解决方案要等到 Go 拥有原生联合类型之后才会出现。一些人认为联合类型是对格式错误的 JSON 和糟糕设计的回应。

相关文章
  • 在Go语言中解码JSON和值类型,避免恐慌 2025-03-19
  • (评论) 2024-01-06
  • (评论) 2024-05-01
  • (评论) 2023-11-06
  • (评论) 2024-08-03

  • 原文
    Hacker News new | past | comments | ask | show | jobs | submit login
    Decoding JSON sum types in Go without panicking (nicolashery.com)
    21 points by misonic 1 hour ago | hide | past | favorite | 6 comments










    Cool but all you really needed to do was fix the contract between NewActionDeleteObject’s struct creation and the switch statements result = print. What’s really crazy is you can create anonymous structs to unmarshal json without having to fully flesh out data models thanks to its “we’ll only map the fields we see in the struct” approach. Mapstructure takes this even further with squash. In the end, the type checker missed the error because it was user error by contract and that, due to lack of validation that the actions were constructed properly, resulted in a rabbit hole debugging session that ended with an excellent blog post about the gotchas of unmarshaling.


    > human error

    Humans suck at formalisms.

    When XML was the 'sane choice' I grew to hate it, until I met a person who introduced me to XMLSpy. It has a mode where instead of trying to define the schema you offer it example documents and it offers you a schema that seems to satisfy your examples, at which point you can either switch to manual or provide more examples. He was right, it did make me hate XML a lot less.

    At least until the next job when they wouldn't pay for it.



    IME this is a longstanding pain point with Go. There's an attempt to propose an encoding/json/v2 package [1] being kicked around at the moment [2], spawned from a discussion [3].

    This at least seems to improve the situation of marshalling to/from an interface directly slightly by providing the ability to pass custom Unmarshalers for a specific type (via json.WithUnmarshalers and json.UnmarshalFunc) to the Unmarshal functions, but it appears to still have the inefficient double-decode problem. Or I just haven't found a decent way around it yet.

    Looks like they're intentionally punting on a first class solution until (if) the language gets some sort of sum type, but I still think the second-class solution could do a bit more to make this extremely common use-case more convenient. Pretty much every serious production Go app I've worked on in the last 10 years or so has had some horrible coping strategy for the "map a field-discriminated object to/from implementations of an interface" gap.

    Quote from the proposal [1]:

    > First-class support for union types: It is common for the type of a particular JSON value to be dynamically changed based on context. This is difficult to support in Go as the equivalent of a dynamic value is a Go interface. When unmarshaling, there is no way in Go reflection to enumerate the set of possible Go types that can be stored in a Go interface in order to choose the right type to automatically unmarshal a dynamic JSON value. Support for such use cases is deferred until better Go language support exists.

      [1]: https://pkg.go.dev/github.com/go-json-experiment/json
      [2]: https://github.com/golang/go/issues/71497
      [3]: https://github.com/golang/go/discussions/63397


    BTW double unmarshalling (and double marshalling) can be quite slow, so to speed up determining the object type you can extract the type field e.g. by using gjson (https://github.com/tidwall/gjson). It can be easily 10x faster for this kind of scenario


    Pulled my hair out about doing this all over the place when integrating with a node api, ended up writing https://github.com/byrnedo/pjson. Feels like this should be covered as a more first class thing in go.


    Reading the article I got the same conclusion as every time I approach sum types: they are ONLY useful for addressing malformed JSON structs of hacking BAD data structure/logic design, at least for most business applications (for system-level programs my reasoning is different).

    The example JSON in the article, even if it may be common, is broken and I would not accept such design, because an action on an object must require the action AND the object.

    For many year, I have advised companies developing business applications to avoid programming constructs (like sum types) which are very far from what a business man would understand (think of a business form in paper for the first example in the article). And the results are good, making the business logic in the program as similar as possible to the business logic in terms of business people.







    Join us for AI Startup School this June 16-17 in San Francisco!


    Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact



    Search:
    联系我们 contact @ memedata.com