マップは値によって渡されますか、それともGoで参照によって渡されますか?


94

マップはGoで値または参照によって渡されますか?

関数を次のように定義することは常に可能ですが、これはやり過ぎですか?

func foo(dat *map[string]interface{}) {...}

戻り値についても同じ質問です。マップへのポインタを返す必要がありますか、それともマップを値として返す必要がありますか?

もちろん、不要なデータのコピーを回避することを目的としています。


4
blog.golang.org/go-maps-in-action:マップタイプはポインターやスライスなどの参照型であるため、上記のmの値はnilです。初期化されたマップを指していません。nilマップは、読み取り時には空のマップのように動作しますが、nilマップに書き込もうとすると、ランタイムパニックが発生します。そうしないでください。マップを初期化するには、組み込みのmake関数を使用します
mh-cbon 2016年

2
Goのすべては値によって渡されます。一部の値は、たまたまポインター、またはポインターを含む構造体です。(*map住所でマップ値を再割り当てする必要がある場合は、が必要になることがあります)
JimB 2016年

mh-cbon、Goには参照型はありません。
InancGumus19年

@ mh-cbon私は参照型について話していませんでした。マップが参照によって渡されるかどうかを尋ねていました。これは、マップのアドレスが引数として渡されるのか、マップの「コピー」(値によって渡される)として渡されるのかを尋ねるのと同じです。
chmike

1
@ mh-cbonまさに、マップはhmapへのポインターです。
InancGumus19年

回答:


83

このスレッドであなたはあなたの答えを見つけるでしょう:

Golang:参照を使用して地図にアクセスする

マップでポインタを使用する必要はありません。

マップタイプは、ポインタやスライスなどの参照タイプです[1]

セッションを変更する必要がある場合は、ポインタを使用できます。

map[string]*Session

https://blog.golang.org/go-maps-in-action


16
落とし穴を避けるために、マップは初期化された後にのみ参照によって渡され、関数内で再初期化された場合、元の参照は更新されないことに注意してください。遊び場の例を次に示します。play.golang.org / p / Q6vrAmmJWR6 またはDaveChenyによる完全な記事dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren 2018

19

ここからいくつかの部分であり、マップが参照変数ではない場合には、それは何ですか?デイブ・チェイニー著:

マップ値は、runtime.hmap構造体へのポインターです。

と結論:

結論

マップはチャネルと同様ですが、スライスとは異なり、ランタイムタイプへの単なるポインタです。上で見たように、マップはruntime.hmap 構造への単なるポインタです。

マップには、Goプログラムの他のポインター値と同じポインターセマンティクスがあります。コンパイラによるマップ構文の書き換えをの関数の呼び出しに保存する魔法はありませんruntime/hmap.go

そして、map構文の歴史/説明についての興味深いビット:

マップがポインタである場合、そうではありません*map[key]valueか?

マップがポインタ値でmake(map[int]int)ある場合、式がタイプが値を返すのは なぜかというのは良い質問ですmap[int]int。それは返すべきではありません*map[int]intか?Ian Taylor は最近、golang-nutsスレッド1でこれに答えました

非常に初期の頃、私たちがマップと呼んでいるものはポインタとして書かれていたので、あなたは書いた*map[int]int。誰mapも書くことなしに書くことはないことに気づいたとき、私たちはそれから離れました*map

おそらく、型の名前をから*map[int]intに変更するmap[int]intと、型がポインタのように見えないため混乱しますが、逆参照できないポインタ型の値よりも混乱が少なくなりました。


3

いいえ。デフォルトではマップは参照です。

    package main

    import "fmt"

    func mapToAnotherFunction(m map[string]int) {
        m["hello"] = 3
        m["world"] = 4
        m["new_word"] = 5
    }

    // func mapToAnotherFunctionAsRef(m *map[string]int) {
    // m["hello"] = 30
    // m["world"] = 40
    // m["2ndFunction"] = 5
    // }

    func main() {
        m := make(map[string]int)
        m["hello"] = 1
        m["world"] = 2

        // Initial State
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        fmt.Println("-----------------------")

        mapToAnotherFunction(m)
        // After Passing to the function as a pointer
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        // Try Un Commenting This Line
        fmt.Println("-----------------------")

        // mapToAnotherFunctionAsRef(&m)
        // // After Passing to the function as a pointer
        // for key, val := range m {
        //  fmt.Println(key, "=>", val)
        // }

        // Outputs
        // hello => 1
        // world => 2
        // -----------------------
        // hello => 3
        // world => 4
        // new_word => 5
        // -----------------------

    }

Golangブログから-

マップタイプはポインタやスライスなどの参照型であるため、上記のmの値はnilです。初期化されたマップを指していません。nilマップは、読み取り時には空のマップのように動作しますが、nilマップに書き込もうとすると、ランタイムパニックが発生します。そうしないでください。マップを初期化するには、組み込みのmake関数を使用します。

// Ex of make function
m = make(map[string]int)

コードスニペットリンクそれで遊んでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.