使用方法返回作为字段的JSON Marshal结构体

huangapple go评论128阅读模式
英文:

JSON Marshal struct with method return as field

问题

可以将具有方法返回值作为字段的结构进行编组吗?例如,我想要以下JSON:

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

使用以下类型的结构:

  1. type Deck struct {
  2. Cards []int `json:"cards"`
  3. Value func() int `json:"value"`
  4. Size func() int `json:"size"`
  5. }

有人知道吗?

英文:

Is it possible to marshal a struct with method return as field? For example, I want this JSON

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

With this kind of struct

  1. type Deck struct {
  2. Cards []int `json:"cards"`
  3. Value func() int `json:"value"`
  4. Size func() int `json:"size"`
  5. }

Anyone?

答案1

得分: 15

你可以实现一个类似这样的Marshaler,代码示例可以在这里找到:http://play.golang.org/p/ySUFcUOHCZ(或者这里:http://play.golang.org/p/ndwKu-7Y5m)。

  1. package main
  2. import "fmt"
  3. import "encoding/json"
  4. type Deck struct {
  5. Cards []int
  6. }
  7. func (d Deck) Value() int {
  8. value := 0
  9. for _, v := range d.Cards {
  10. value = value + v
  11. }
  12. return value
  13. }
  14. func (d Deck) Size() int {
  15. return len(d.Cards)
  16. }
  17. func (d Deck) MarshalJSON() ([]byte, error) {
  18. return json.Marshal(struct {
  19. Cards []int `json:"cards"`
  20. Value int `json:"value"`
  21. Size int `json:"size"`
  22. }{
  23. Cards: d.Cards,
  24. Value: d.Value(),
  25. Size: d.Size(),
  26. })
  27. }
  28. func main() {
  29. deck := Deck{
  30. Cards: []int{1, 2, 3},
  31. }
  32. b, r := json.Marshal(deck)
  33. fmt.Println(string(b))
  34. fmt.Println(r)
  35. }
英文:

You can implement a Marshaler like this http://play.golang.org/p/ySUFcUOHCZ (or this http://play.golang.org/p/ndwKu-7Y5m )

<!-- language: lang-go -->

  1. package main
  2. import &quot;fmt&quot;
  3. import &quot;encoding/json&quot;
  4. type Deck struct {
  5. Cards []int
  6. }
  7. func (d Deck) Value() int {
  8. value := 0
  9. for _, v := range d.Cards {
  10. value = value + v
  11. }
  12. return value
  13. }
  14. func (d Deck) Size() int {
  15. return len(d.Cards)
  16. }
  17. func (d Deck) MarshalJSON() ([]byte, error) {
  18. return json.Marshal(struct {
  19. Cards []int `json:&quot;cards&quot;`
  20. Value int `json:&quot;value&quot;`
  21. Size int `json:&quot;size&quot;`
  22. }{
  23. Cards: d.Cards,
  24. Value: d.Value(),
  25. Size: d.Size(),
  26. })
  27. }
  28. func main() {
  29. deck := Deck{
  30. Cards: []int{1, 2, 3},
  31. }
  32. b, r := json.Marshal(deck)
  33. fmt.Println(string(b))
  34. fmt.Println(r)
  35. }

答案2

得分: 1

你还可以创建一个实现了JSONMarshaler和JSONUnmarshaler接口的函数类型。但是它有一些缺点。

  1. import "fmt"
  2. import "encoding/json"
  3. type IntFunc func() int
  4. func (f IntFunc) MarshalJSON() ([]byte, error) {
  5. return json.Marshal(f())
  6. }
  7. // 注意:在这里你将失去原始函数
  8. func (f *IntFunc) UnmarshalJSON(b []byte) error {
  9. var i int
  10. err := json.Unmarshal(b, &i)
  11. // 你可以添加一个虚拟函数,或者通过不给*f赋值来将其保持为nil
  12. *f = func() int { return i }
  13. return err
  14. }
  15. type Deck struct {
  16. Cards []int `json:"cards"`
  17. Value IntFunc `json:"value"`
  18. Size IntFunc `json:"size"`
  19. }
  20. func main() {
  21. deck := Deck{
  22. Cards: []int{1, 2, 3},
  23. }
  24. deck.Value = ValueOf(&deck)
  25. deck.Size = SizeOf(&deck)
  26. fmt.Printf("Size: %v, Cards: %v, Value: %v\n", deck.Size(), deck.Cards, deck.Value())
  27. deck.Cards = append(deck.Cards, 8)
  28. fmt.Printf("Size: %v, Cards: %v, Value: %v\n", deck.Size(), deck.Cards, deck.Value())
  29. fmt.Println()
  30. b, err := json.Marshal(deck)
  31. fmt.Println("Marshal Error:", err)
  32. fmt.Println("Marshal result:", string(b))
  33. fmt.Println()
  34. var d2 Deck
  35. err = json.Unmarshal([]byte(`{"cards":[1,2,3,8],"value":14,"size":4}`), &d2)
  36. fmt.Println("Unmarshal Error =>", err)
  37. fmt.Printf("Unmarshal Result => Size: %v, Cards: %v, Value: %v\n", d2.Size(), d2.Cards, d2.Value()) // 如果Size()和Value()为nil,可能会抛出错误
  38. }
  39. func SizeOf(d *Deck) IntFunc {
  40. return func() int {
  41. return len(d.Cards)
  42. }
  43. }
  44. func ValueOf(d *Deck) IntFunc {
  45. return func() int {
  46. i := 0
  47. for _, v := range d.Cards {
  48. i += v
  49. }
  50. return i
  51. }
  52. }
英文:

You could also create a function type that implement JSONMarshaler and JSONUnmarshaler. But it has some drawbacks.

  1. import &quot;fmt&quot;
  2. import &quot;encoding/json&quot;
  3. type IntFunc func() int
  4. func (f IntFunc) MarshalJSON() ([]byte, error) {
  5. return json.Marshal(f())
  6. }
  7. // NOTES you&#39;ll lose the original function here
  8. func (f *IntFunc) UnmarshalJSON(b []byte) error {
  9. var i int
  10. err := json.Unmarshal(b, &amp;i)
  11. // you could either add dummy function or leave it nil by not assigning *f
  12. *f = func() int { return i }
  13. return err
  14. }
  15. type Deck struct {
  16. Cards []int `json:&quot;cards&quot;`
  17. Value IntFunc `json:&quot;value&quot;`
  18. Size IntFunc `json:&quot;size&quot;`
  19. }
  20. func main() {
  21. deck := Deck{
  22. Cards: []int{1, 2, 3},
  23. }
  24. deck.Value = ValueOf(&amp;deck)
  25. deck.Size = SizeOf(&amp;deck)
  26. fmt.Printf(&quot;Size: %v, Cards: %v, Value: %v\n&quot;, deck.Size(), deck.Cards, deck.Value())
  27. deck.Cards = append(deck.Cards, 8)
  28. fmt.Printf(&quot;Size: %v, Cards: %v, Value: %v\n&quot;, deck.Size(), deck.Cards, deck.Value())
  29. fmt.Println()
  30. b, err := json.Marshal(deck)
  31. fmt.Println(&quot;Marshal Error:&quot;, err)
  32. fmt.Println(&quot;Marshal result:&quot;, string(b))
  33. fmt.Println()
  34. var d2 Deck
  35. err = json.Unmarshal([]byte(`{&quot;cards&quot;:[1,2,3,8],&quot;value&quot;:14,&quot;size&quot;:4}`), &amp;d2)
  36. fmt.Println(&quot;Unmarshal Error =&gt;&quot;, err)
  37. fmt.Printf(&quot;Unmarshal Result =&gt; Size: %v, Cards: %v, Value: %v\n&quot;, d2.Size(), d2.Cards, d2.Value()) // could throw error if Size() and Value() is nil
  38. }
  39. func SizeOf(d *Deck) IntFunc {
  40. return func() int {
  41. return len(d.Cards)
  42. }
  43. }
  44. func ValueOf(d *Deck) IntFunc {
  45. return func() int {
  46. i := 0
  47. for _, v := range d.Cards {
  48. i += v
  49. }
  50. return i
  51. }
  52. }

答案3

得分: 0

通常情况下是可以的。你需要使用reflect包,并且基本上编写自己的编组器。

但是使用Go的encoding/json包就不需要了。

英文:

In general, yes. You'd have to use the the reflect package and essentially write your own marshaller.

With Go's encoding/json package, no.

huangapple
  • 本文由 发表于 2015年8月6日 14:59:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/31848836.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定