我来自 Python/Ruby/JavaScript 背景。我了解指针的工作原理,但是,我不完全确定如何在以下情况下利用它们。
假设我们有一个虚构的 Web API,它搜索一些图像数据库并返回一个 JSON 描述在找到的每个图像中显示的内容:
[
{
"url": "https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg",
"description": "Ocean islands",
"tags": [
{"name":"ocean", "rank":1},
{"name":"water", "rank":2},
{"name":"blue", "rank":3},
{"name":"forest", "rank":4}
]
},
...
{
"url": "https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg",
"description": "Bridge over river",
"tags": [
{"name":"bridge", "rank":1},
{"name":"river", "rank":2},
{"name":"water", "rank":3},
{"name":"forest", "rank":4}
]
}
]
我的目标是在 Go 中创建一个数据结构,它将每个标签映射到一个图像 URL 列表,如下所示:
{
"ocean": [
"https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg"
],
"water": [
"https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg",
"https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg"
],
"blue": [
"https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg"
],
"forest":[
"https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg",
"https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg"
],
"bridge": [
"https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg"
],
"river":[
"https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg"
]
}
如您所见,每个图像 URL 可以同时属于多个标签。如果我有数千张图像甚至更多标签,如果图像 URL 字符串按每个标签的值复制,则此数据结构可能会变得非常大。这是我想利用指针的地方。
我可以用 Go 中的两个结构来表示 JSON API 响应,func searchImages()
模仿假 API:
package main
import "fmt"
type Image struct {
URL string
Description string
Tags []*Tag
}
type Tag struct {
Name string
Rank int
}
// this function mimics json.NewDecoder(resp.Body).Decode(&parsedJSON)
func searchImages() []*Image {
parsedJSON := []*Image{
&Image {
URL: "https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg",
Description: "Ocean islands",
Tags: []*Tag{
&Tag{"ocean", 1},
&Tag{"water", 2},
&Tag{"blue", 3},
&Tag{"forest", 4},
},
},
&Image {
URL: "https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg",
Description: "Bridge over river",
Tags: []*Tag{
&Tag{"bridge", 1},
&Tag{"river", 2},
&Tag{"water", 3},
&Tag{"forest", 4},
},
},
}
return parsedJSON
}
现在,导致内存中数据结构非常大的次优映射函数可能如下所示:
func main() {
result := searchImages()
tagToUrlMap := make(map[string][]string)
for _, image := range result {
for _, tag := range image.Tags {
// fmt.Println(image.URL, tag.Name)
tagToUrlMap[tag.Name] = append(tagToUrlMap[tag.Name], image.URL)
}
}
fmt.Println(tagToUrlMap)
}
我可以修改它以使用指向Image
结构URL
字段的指针,而不是按值复制它:
// Version 1
tagToUrlMap := make(map[string][]*string)
for _, image := range result {
for _, tag := range image.Tags {
// fmt.Println(image.URL, tag.Name)
tagToUrlMap[tag.Name] = append(tagToUrlMap[tag.Name], &image.URL)
}
}
它有效,我的第一个问题是result
在我以这种方式构建映射后数据结构会发生什么?字符串字段会Image
URL
以某种方式留在内存中,其余的result
将被垃圾收集吗?或者result
数据结构是否会因为某些东西指向它的成员而保留在内存中直到程序结束?
另一种方法是将 URL 复制到中间变量并使用指向它的指针:
// Version 2
tagToUrlMap := make(map[string][]*string)
for _, image := range result {
imageUrl = image.URL
for _, tag := range image.Tags {
// fmt.Println(image.URL, tag.Name)
tagToUrlMap[tag.Name] = append(tagToUrlMap[tag.Name], &imageUrl)
}
}
这是否更好?数据结构会result
被正确地垃圾收集吗?
或者也许我应该在结构中使用指向字符串的指针Image
?
type Image struct {
URL *string
Description string
Tags []*Tag
}
有一个更好的方法吗?我也很感激 Go 上的任何资源,这些资源深入描述了指针的各种用途。谢谢!
https://play.golang.org/p/VcKWUYLIpH7
更新:我担心最佳的内存消耗并且不会产生最不需要的垃圾。我的目标是尽可能使用最少的内存。