英文:
Why does Go error when trying to marshal this JSON?
问题
我正在尝试一个相当简单的示例,使用golang将JSON文件解码为一些结构体。然而,当我尝试时,我得到了以下错误:
json: 无法将对象解组为类型为[]main.Track的Go值
我不明白这个错误的原因。以下是相关的代码,JSON可以在这里找到。
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
// Tracks a group of Track types
type Tracks struct {
Tracks []Track
}
// Track represents a singular track
type Track struct {
Name string
URL string
Artist Artist
}
// Artist represents a single artist
type Artist struct {
Name string
MBID string
URL string
}
func main() {
url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands"
response, err := http.Get(url)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
defer response.Body.Close()
var tracks Tracks
decodeErr := json.NewDecoder(response.Body).Decode(&tracks)
if decodeErr != nil {
fmt.Printf("%s\n", decodeErr)
os.Exit(1)
}
for _, track := range tracks.Tracks {
fmt.Printf("%s: %s\n", track.Artist.Name, track.Name)
}
}
我最初的想法是也许你需要使用结构体对每个JSON值进行分类,但我没有这样做。但在阅读了这篇文章后,我发现:
对于这个问题有两个答案。简单的选项是,当你知道数据的结构时,将JSON解析为你定义的结构体。**任何不适合结构体的字段都将被忽略。**我们先介绍这个选项。
这让我相信问题不在于这个。
在这种情况下,我做错了什么?
英文:
I'm trying a rather simple example of trying to decode a JSON file into some structs using golang. However, when attempting to I get the error that
> json: cannot unmarshal object into Go value of type []main.Track
Which I don't understand. Here's the code in question, and the JSON can be found here.
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
// Tracks a group of Track types
type Tracks struct {
Tracks []Track
}
// Track represents a singular track
type Track struct {
Name string
URL string
Artist Artist
}
// Artist represents a single artist
type Artist struct {
Name string
MBID string
URL string
}
func main() {
url := "http://ws.audioscrobbler.com/2.0/?method=geo.gettoptracks&api_key=c1572082105bd40d247836b5c1819623&format=json&country=Netherlands"
response, err := http.Get(url)
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
defer response.Body.Close()
var tracks Tracks
decodeErr := json.NewDecoder(response.Body).Decode(&tracks)
if decodeErr != nil {
fmt.Printf("%s\n", decodeErr)
os.Exit(1)
}
for _, track := range tracks.Tracks {
fmt.Printf("%s: %s\n", track.Artist.Name, track.Name)
}
}
My initial thought was maybe you need to categorize every single JSON value with structs, which I didn't do, but upon reading this article which says:
> There are two answers to this. The easy option, for when you know what your data will look like, is to parse the JSON into a struct you’ve defined. Any field which doesn’t fit in the struct will just be ignored. We’ll cover that option first.
Which leads me to believe that it isn't that.
What am I doing wrong in this scenario?
答案1
得分: 1
如果你查看响应的 JSON 结构,你会发现返回的是一个带有 tracks
属性的单个对象。
{
"tracks": {
"track": [ {...} ]
}
}
如果你将其与给定的结构进行比较,你会发现结构不一致。你给出的 Tracks
结构有一个字段,它是 Track
的切片。如果我将其转换为 JSON,它将表示为以下内容。
{
"tracks": [ { ... } ]
}
这是你错误的根源。JSON 解码器期望根 JSON 对象的 tracks
字段是一个数组。但实际返回的是一个包含 tracks
属性的对象,而其值是另一个 JSON 对象,其中包含 track
属性,它是一组轨迹的数组。你可以更新你的结构以反映这个模式,如下所示。
// 来自 API 的响应对象
type Response struct {
Tracks Tracks
}
// Tracks 表示一组 Track 类型
type Tracks struct {
Track []Track
}
// Track 表示一个单独的轨迹
type Track struct {
Name string
URL string
Artist Artist
}
英文:
If you look at the JSON structure of the response to your query you'll see that a single object with a tracks
property is returned.
{
"tracks": {
"track": [ {...} ]
}
}
If you compare this to to the given structs you can see that the structure does not align. Your given Tracks
struct has a field that is a slice of Track
s. If I were to cast this as JSON it would be represented as the following.
{
"tracks": [ { ... } ]
}
This is the root of your error. The JSON decoder is expecting the tracks
field of the root JSON object to be an array. What is returned is an object that contains the tracks
property but its values is another JSON object which contains the track
property which is the array of tracks. You could update your structures to reflect this schema as follows.
// A response object from the API
type Response struct {
Tracks Tracks
}
// Tracks a group of Track types
type Tracks struct {
Track []Track
}
// Track represents a singular track
type Track struct {
Name string
URL string
Artist Artist
}
答案2
得分: 0
Go类型的结构必须与JSON数据中的结构匹配。该应用程序在此JSON的粗体范围中缺少一层嵌套:{"tracks":{"track":[{
以下是如何更新类型以匹配JSON的方法:
type Tracks struct {
Tracks struct {
Track []Track
}
}
...
for _, track := range tracks.Tracks.Track {
fmt.Printf("%s: %s\n", track.Artist.Name, track.Name)
}
英文:
The structure of the Go types must match the structure in the JSON data. The application is missing a level of nesting for the bolded range of this JSON: {"tracks":{"track":[{
Here's how to update the types to match the JSON:
type Tracks struct {
Tracks struct {
Track []Track
}
}
...
for _, track := range tracks.Tracks.Track {
fmt.Printf("%s: %s\n", track.Artist.Name, track.Name)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论