8

私は Python/Ruby/JavaScript のバックグラウンドを持っています。ポインターがどのように機能するかは理解していますが、次の状況でそれらを活用する方法が完全にはわかりません。

画像データベースを検索し、見つかった各画像に何が表示されているかを説明する JSON を返す架空の Web API があるとします。

[
    {
        "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}
        ]
    }
]

私の目標は、各タグを次のような画像 URL のリストにマップするデータ構造を Go で作成することです。

{
    "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 の 2 つの構造体で 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

更新:最適なメモリ消費と、不要なガベージを最も生成しないことが心配です。私の目標は、可能な限り最小限のメモリを使用することです。

4

2 に答える 2