Golang无法将结构体数组或切片字面量用作类型。

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

Golang cannot use as type struct array or slice literal

问题

我正在尝试在Go中编写一个函数,该函数接受一个包含目录URL的JSON,并执行BFS以查找该目录中的文件。当我找到一个JSON是目录时,代码会创建一个URL并将该URL加入队列。当我尝试在循环中的append()中创建结构体时,出现了错误。

type ContentResp []struct {
    Name         string `json:"name"`
    ContentType  string `json:"type"`
    DownloadURL  string `json:"download_url"`
}
...

var contentResp ContentResp
search(contentQuery, &contentResp)

for _, cont := range contentResp {
    append(contentResp, ContentResp{Name: cont.Name, ContentType: "dir", DownloadURL: cont.contentDir.String()})
}

./bfs.go:129: undefined: Name
./bfs.go:129: cannot use cont.Name (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal
./bfs.go:129: undefined: ContentType
./bfs.go:129: cannot use "dir" (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal
./bfs.go:129: undefined: DownloadURL
./bfs.go:129: cannot use cont.contentDir.String() (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal

这些错误是由于在append()函数中创建结构体时出现了问题。你需要确保结构体字段的名称和类型与定义的结构体字段一致。

英文:

I'm trying to write a function in Go that takes a JSON with URLs of a directory and perform BFS to find files in that directory. When I find a JSON that is a directory, the code makes a URL and should enqueue that URL. When I try to create the struct in the append() in the loop, I get errors.

type ContentResp []struct {
    Name string `json:"name"`
    ContentType string `json:"type"`
    DownloadURL string `json:"download_url"`
}
...

var contentResp ContentResp
search(contentQuery, &contentResp)

for _, cont := range contentResp {
        append(contentResp, ContentResp{Name:cont.Name, ContentType:"dir", DownloadURL:cont.contentDir.String()})
}

./bfs.go:129: undefined: Name
./bfs.go:129: cannot use cont.Name (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal
./bfs.go:129: undefined: ContentType
./bfs.go:129: cannot use "dir" (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal
./bfs.go:129: undefined: DownloadURL
./bfs.go:129: cannot use cont.contentDir.String() (type string) as type struct { Name string "json:\"name\""; ContentType string "json:\"type\""; DownloadURL string "json:\"download_url\"" } in array or slice literal  

答案1

得分: 7

你的ContentResp类型是一个切片(slice),而不是一个结构体(struct),但是当你使用复合字面量尝试创建一个值时,你却将其当作结构体来处理:

type ContentResp []struct {
    // ...
}

更准确地说,它是一个匿名结构体的切片。创建匿名结构体的值是不方便的,所以你应该创建(命名)一个只包含struct的类型,并使用该类型的切片,例如:

type ContentResp struct {
    Name        string `json:"name"`
    ContentType string `json:"type"`
    DownloadURL string `json:"download_url"`
}

var contentResps []ContentResp

进一步的问题:

让我们来看看这个循环:

for _, cont := range contentResp {
    append(contentResp, ...)
}

上面的代码遍历一个切片,并在其中尝试追加元素到切片中。这里有两个问题:append()返回的结果必须被存储(它甚至可能需要分配一个新的、更大的支持数组,并将现有元素复制过去,在这种情况下,结果切片将指向一个完全不同的数组,旧的数组应该被丢弃)。所以应该像这样使用:

contentResps = append(contentResps, ...)

其次:你不应该改变你正在遍历的切片。for ... range只会对范围表达式进行一次求值(最多一次),所以你对它进行的更改(添加元素)对迭代器代码没有影响(它不会看到切片头的变化)。

如果你有这样的情况,即在执行过程中可能出现新的任务(需要递归完成),那么使用通道是一个更好的解决方案。查看这个答案,以了解通道的用途:https://stackoverflow.com/questions/39826692/what-are-golang-channels-used-for/39826883#39826883

英文:

Your ContentResp type is a slice, not a struct, yet you're treating it as a struct when you use a composite literal trying to create a value of it:

type ContentResp []struct {
    // ...
}

More precisely it's a slice of a type which is an anonymous struct. Creating values of anonymous structs are unpleasant, so instead you should create (name) a type being only the struct, and use a slice of this, e.g.:

type ContentResp struct {
    Name        string `json:"name"`
    ContentType string `json:"type"`
    DownloadURL string `json:"download_url"`
}

var contentResps []ContentResp

Further issues:

Let's examine this loop:

for _, cont := range contentResp {
    append(contentResp, ...)
}

The code above ranges over a slice, and inside it it tries to append elements to the slice. 2 issues with this: append() returns the result which must be stored (it might even have to allocate a new, bigger backing array and copy existing elements over, in which case the result slice will point to a completely different array and the old one should be abandoned). So it should be used like this:

    contentResps = append(contentResps, ...)

Second: you shouldn't change the slice you're ranging over. The for ... range evaluates the range expression once (at most), so you changing it (adding elements to it) will have no effect to the iterator code (it will not see the slice header changes).

If you have such a case where you have "tasks" to be completed, but during execution new tasks may arise (to be completed, recursively), a channel is a much better solution. See this answer to get a feeling of channels: https://stackoverflow.com/questions/39826692/what-are-golang-channels-used-for/39826883#39826883

huangapple
  • 本文由 发表于 2016年12月28日 05:13:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/41352295.html
匿名

发表评论

匿名网友

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

确定