【问题标题】:JSON Marshal struct with method return as fieldJSON Marshal 结构,方法返回为字段
【发布时间】:2021-11-01 05:27:46
【问题描述】:

是否可以用方法返回作为字段来编组结构?例如,我想要这个 JSON

{
  "cards": [1,2,3],
  "value": 6,
  "size": 3
}

有了这种结构

type Deck struct {
   Cards []int    `json:"cards"`
   Value func() int `json:"value"`
   Size  func() int `json:"size"`
}

有人吗?

【问题讨论】:

  • 不,这需要编程。也许 github.com/vdobler/export 中的格式化程序就足够了。
  • 好的,谢谢。那么,在不包括依赖项的情况下,最好的方法是什么?
  • Deck.ValueDeck.Size字段,而不是方法;函数类型的字段。

标签: json go marshalling


【解决方案1】:

您可以像这样http://play.golang.org/p/ySUFcUOHCZ(或这样http://play.golang.org/p/ndwKu-7Y5m)实现Marshaler

package main

import "fmt"
import "encoding/json"

type Deck struct {
    Cards []int
}

func (d Deck) Value() int {
    value := 0
    for _, v := range d.Cards {
        value = value + v
    }
    return value
}
func (d Deck) Size() int {
    return len(d.Cards)
}

func (d Deck) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        Cards []int `json:"cards"`
        Value int   `json:"value"`
        Size  int   `json:"size"`
    }{
        Cards: d.Cards,
        Value: d.Value(),
        Size:  d.Size(),
    })
}

func main() {
    deck := Deck{
        Cards: []int{1, 2, 3},
    }

    b, r := json.Marshal(deck)
    fmt.Println(string(b))
    fmt.Println(r)
}

【讨论】:

  • 哦,太好了!但是......不是非常有用,因为我想计算同一结构内卡片的值。 IntFuncJson 必须是方法而不是经典函数。 func (d *Deck) Value() int
  • 没有第一个漂亮的解决方案,但肯定是最好的方法。谢谢 ! (MarshalJSON 函数中的值计算是没有用的不是吗?)
  • 我建议这种方法更抽象一点:play.golang.org/p/fdlwiPA_K2Y
【解决方案2】:

您还可以创建实现 JSONMarshaler 和 JSONUnmarshaler 的函数类型。但它有一些缺点。


import "fmt"
import "encoding/json"

type IntFunc func() int

func (f IntFunc) MarshalJSON() ([]byte, error) {
    return json.Marshal(f())
}

// NOTES you'll lose the original function here
func (f *IntFunc) UnmarshalJSON(b []byte) error {
    var i int
    err := json.Unmarshal(b, &i)

    // you could either add dummy function or leave it nil by not assigning *f
    *f = func() int { return i }
    return err
}

type Deck struct {
    Cards []int   `json:"cards"`
    Value IntFunc `json:"value"`
    Size  IntFunc `json:"size"`
}

func main() {
    deck := Deck{
        Cards: []int{1, 2, 3},
    }
    deck.Value = ValueOf(&deck)
    deck.Size = SizeOf(&deck)

    fmt.Printf("Size: %v, Cards: %v, Value: %v\n", deck.Size(), deck.Cards, deck.Value())
    deck.Cards = append(deck.Cards, 8)
    fmt.Printf("Size: %v, Cards: %v, Value: %v\n", deck.Size(), deck.Cards, deck.Value())
    fmt.Println()

    b, err := json.Marshal(deck)
    fmt.Println("Marshal Error:", err)
    fmt.Println("Marshal result:", string(b))
    fmt.Println()

    var d2 Deck
    err = json.Unmarshal([]byte(`{"cards":[1,2,3,8],"value":14,"size":4}`), &d2)
    fmt.Println("Unmarshal Error =>", err)
    fmt.Printf("Unmarshal Result => Size: %v, Cards: %v, Value: %v\n", d2.Size(), d2.Cards, d2.Value()) // could throw error if Size() and Value() is nil
}

func SizeOf(d *Deck) IntFunc {
    return func() int {
        return len(d.Cards)
    }
}

func ValueOf(d *Deck) IntFunc {
    return func() int {
        i := 0
        for _, v := range d.Cards {
            i += v
        }
        return i

    }
}

【讨论】:

    【解决方案3】:

    一般来说,是的。您必须使用 reflect package 并基本上编写自己的编组器。

    使用 Go 的 encoding/json 包,没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多