使用jsonapi将切片进行编组

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

Marshal slice with jsonapi

问题

我有一个结构体切片,我想使用https://github.com/google/jsonapi进行编组。

对于单个结构体,一切都正常。我只需将指针作为第二个参数传递即可。

package main

import (
	"fmt"
	"os"

	"github.com/google/jsonapi"
)

type Spider struct {
	ID       int `jsonapi:"primary,spiders"`
	EyeCount int `jsonapi:"attr,eye_count"`
}

func main() {
	jsonapi.MarshalPayload(os.Stdout, &Spider{ID: 2, EyeCount: 12})
    // {"data":{"type":"spiders","id":"2","attributes":{"eye_count":12}}}
}

然而,当我尝试对切片进行相同操作时,情况就有所不同。

首先,我将我的切片转换为指向这些结构体的指针切片(不知道还能做什么,将切片的指针传递给函数并不起作用)。

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}

var spiderPointers []*Spider
for _, x := range spiders {
	spiderPointers = append(spiderPointers, &x)
}
jsonapi.MarshalPayload(os.Stdout, spiderPointers)

这样做是可以的。有个问题:

{"data":[
  {"type":"spiders","id":"2","attributes":{"eye_count":12}},
  {"type":"spiders","id":"2","attributes":{"eye_count":12}}]}

最后一个元素重复了,并且替换了其他元素。

最后,我想出了一个基本可行的解决方案:

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}
var spiderPointers []interface{}
for _, x := range spiders {
	var spider Spider
	spider = x
	spiderPointers = append(spiderPointers, &spider)
}

jsonapi.MarshalPayload(os.Stdout, spiderPointers)
// {"data":[{"type":"spiders","id":"1","attributes":{"eye_count":8}},
//          {"type":"spiders","id":"2","attributes":{"eye_count":12}}]}

但我相信一定有更好的方法,因此提出了这个问题。

英文:

I have a slice of structs and I want to marshal it using https://github.com/google/jsonapi.

With a single struct, everything works fine. I simply pass a pointer as a second argument.

package main

import (
	"fmt"
	"os"

	"github.com/google/jsonapi"
)

type Spider struct {
	ID       int `jsonapi:"primary,spiders"`
	EyeCount int `jsonapi:"attr,eye_count"`
}

func main() {
	jsonapi.MarshalPayload(os.Stdout, &Spider{ID: 2, EyeCount: 12})
    // {"data":{"type":"spiders","id":"2","attributes":{"eye_count":12}}}
}

However, when I'm trying to do the same with a slice, things are quite different.

First of all, I'm converting my slice to a slice of pointers to those structs (don't know what else to do here, passing pointer to the slice didn't work).

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}

var spiderPointers []*Spider
for _, x := range spiders {
	spiderPointers = append(spiderPointers, &x)
}
jsonapi.MarshalPayload(os.Stdout, spiderPointers)

It works. Sort of. Here is the issue:

{"data":[
  {"type":"spiders","id":"2","attributes":{"eye_count":12}},
  {"type":"spiders","id":"2","attributes":{"eye_count":12}}]}

The last element is repeated and it replaces other elements.

In the end, I came up with a somewhat working solution:

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}
var spiderPointers []interface{}
for _, x := range spiders {
	var spider Spider
	spider = x
	spiderPointers = append(spiderPointers, &spider)
}

jsonapi.MarshalPayload(os.Stdout, spiderPointers)
// {"data":[{"type":"spiders","id":"1","attributes":{"eye_count":8}},
//          {"type":"spiders","id":"2","attributes":{"eye_count":12}}]}

But I'm sure there must be a better way, hence this question.

答案1

得分: 1

好的,以下是代码的中文翻译:

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/google/jsonapi"
)

type Spider struct {
	ID       int `jsonapi:"primary,spiders"`
	EyeCount int `jsonapi:"attr,eye_count"`
}

func main() {
	// spiders 是一个接口切片.. 如果需要的话,它们可以被反序列化回 spiders
	// 你不需要循环来创建指针... 所以在内存使用上更好,并且更容易阅读.. 根据你提到的从数据库获取这些数据,你也可以使用 for 循环来加载 []interface{}
	var spiders []interface{}
	spiders = append(spiders, &Spider{ID: 1, EyeCount: 8}, &Spider{ID: 2, EyeCount: 12})
	fmt.Println("jsonapi, MarshalPayload")
	jsonapi.MarshalPayload(os.Stdout, spiders)

	// 用于检查缩进的测试
	b, _ := json.MarshalIndent(spiders, "", " ")
	fmt.Println("marshall indent")
	fmt.Println(string(b))
}

希望对你有帮助!

英文:

Curious would you be able to use something like this??

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/google/jsonapi"
)

type Spider struct {
	ID       int `jsonapi:"primary,spiders"`
	EyeCount int `jsonapi:"attr,eye_count"`
}

func main() {
    // spiders is a slice of interfaces.. they can be unmarshalled back to spiders later if the need arises
    // you don't need a loop to create pointers either... so better in memory usage and a bit cleaner to read.. you can in theory load the []interface{} with a for loop as well since you mentioned getting this data from a db
	var spiders []interface{}
	spiders = append(spiders, &Spider{ID: 1, EyeCount: 8}, &Spider{ID: 2, EyeCount: 12})
	fmt.Println("jsonapi, MarshalPayload")
	jsonapi.MarshalPayload(os.Stdout, spiders)

	// test against marshall indent for sanity checking
	b, _ := json.MarshalIndent(spiders, "", " ")
	fmt.Println("marshall indent")
	fmt.Println(string(b))
}

答案2

得分: 0

为什么不这样做 [either3]?

var spiders interface{}
db.Model(spiders).Select()
jsonapi.MarshalPayload(os.Stdout, spiders)
英文:

Why not that way [either3]?

var spiders interface{}
db.Model(spiders).Select()
jsonapi.MarshalPayload(os.Stdout, spiders)

答案3

得分: 0

你遇到的问题是指针问题,而不是jsonapi问题。

当你循环遍历一个值时,循环变量只会被创建一次,然后一遍又一遍地重新赋值。指向循环变量的指针始终指向同一个地址,你只是不断更新值。这导致切片中重复出现相同的指针,而这些指针都指向最后放置在那里的值。

解决方法是创建一个作用域闭包,将值捕获到一个新变量中,然后使用该变量的指针。请尝试以下代码:

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}

var spiderPointers []*Spider
for _, x := range spiders {
    x := x // 捕获循环变量
    spiderPointers = append(spiderPointers, &x)
}
jsonapi.MarshalPayload(os.Stdout, spiderPointers)
英文:

You're running into a pointer issue, not a jsonapi issue.

When you loop over a value, the loop variable is created once and the value is reassigned over and over again. A pointer to a loop variable will always point to the same address and you just keep updating the value. This leaves you with a slice repeating the same pointer all of which point to the last value placed there.

The solution is to create a scoped closure that captures the value in a new variable and then use that variable's pointer. Try the following:

spiders := []Spider{Spider{ID: 1, EyeCount: 8}, Spider{ID: 2, EyeCount: 12}}

var spiderPointers []*Spider
for _, x := range spiders {
    x := x // capture loop variable
    spiderPointers = append(spiderPointers, &x)
}
jsonapi.MarshalPayload(os.Stdout, spiderPointers)

huangapple
  • 本文由 发表于 2017年7月11日 05:17:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/45021734.html
匿名

发表评论

匿名网友

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

确定