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

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

JSON Marshal struct with method return as field

问题

可以将具有方法返回值作为字段的结构进行编组吗?例如,我想要以下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"`
}

有人知道吗?

英文:

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

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

With this kind of struct

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

Anyone?

答案1

得分: 15

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

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)
}
英文:

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 -->

package main

import &quot;fmt&quot;
import &quot;encoding/json&quot;

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:&quot;cards&quot;`
		Value int   `json:&quot;value&quot;`
		Size  int   `json:&quot;size&quot;`
	}{
		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)
}

答案2

得分: 1

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


import "fmt"
import "encoding/json"

type IntFunc func() int

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

// 注意:在这里你将失去原始函数
func (f *IntFunc) UnmarshalJSON(b []byte) error {
	var i int
	err := json.Unmarshal(b, &i)

	// 你可以添加一个虚拟函数,或者通过不给*f赋值来将其保持为nil
	*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()) // 如果Size()和Value()为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

	}
}
英文:

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


import &quot;fmt&quot;
import &quot;encoding/json&quot;

type IntFunc func() int

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

// NOTES you&#39;ll lose the original function here
func (f *IntFunc) UnmarshalJSON(b []byte) error {
	var i int
	err := json.Unmarshal(b, &amp;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:&quot;cards&quot;`
	Value IntFunc `json:&quot;value&quot;`
	Size  IntFunc `json:&quot;size&quot;`
}

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

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

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

	var d2 Deck
	err = json.Unmarshal([]byte(`{&quot;cards&quot;:[1,2,3,8],&quot;value&quot;:14,&quot;size&quot;:4}`), &amp;d2)
	fmt.Println(&quot;Unmarshal Error =&gt;&quot;, err)
	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
}

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

得分: 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:

确定