Карты передаются в Go по значению или по ссылке?

89

В Go карты передаются по значению или по ссылке?

Всегда можно определить функцию следующим образом, но разве это излишество?

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

Тот же вопрос для возвращаемого значения. Должен ли я вернуть указатель на карту или вернуть карту как значение?

Конечно, цель состоит в том, чтобы избежать ненужного копирования данных.

chmike
источник
4
blog.golang.org/go-maps-in-action : типы карт - это ссылочные типы, такие как указатели или срезы, поэтому значение m выше равно нулю; он не указывает на инициализированную карту. При чтении карта nil ведет себя как пустая карта, но попытки записи в карту nil вызовут панику во время выполнения; не делай этого. Для инициализации карты используйте встроенную функцию make
mh-cbon
2
Все в Go передается по значению. Некоторые значения являются указателями или структурами, содержащими указатели. ( *mapв некоторых случаях вам может понадобиться a , если вам нужно переназначить значение карты по адресу)
JimB
mh-cbon, в Go нет ссылочных типов.
Inanc Gumus
@ mh-cbon Я не говорил о ссылочном типе. Я спрашивал, передается ли карта по ссылке, что эквивалентно запросу, передается ли адрес карты как аргумент или «копия» карты (передается по значению).
chmike
1
@ mh-cbon Точно, карты являются указателями на hmap.
Inanc Gumus

Ответы:

79

В этой теме вы найдете свой ответ:

Голанг: доступ к карте по ссылке

Вам не нужно использовать указатель с картой.

Типы карт - это ссылочные типы, например указатели или фрагменты [1]

Если вам нужно изменить сеанс, вы можете использовать указатель:

map[string]*Session

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

Борис Ле Меек
источник
15
Чтобы избежать ошибок, имейте в виду, что карты передаются по ссылке только после инициализации , а при повторной инициализации внутри функции исходная ссылка не будет обновлена. Вот наглядный пример игровой площадки: play.golang.org/p/Q6vrAmmJWR6 Или полная статья Дэйва Чени dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren
18

Вот некоторые части из статьи Если карта не является ссылочной переменной, что это такое? Дэйв Чейни:

Значение карты - это указатель на runtime.hmapструктуру.

и вывод:

Вывод

Карты, как и каналы, но в отличие от срезов, являются просто указателями на типы среды выполнения. Как вы видели выше, карта - это просто указатель на runtime.hmap структуру.

Карты имеют ту же семантику указателя, что и любое другое значение указателя в программе Go. Нет никакого волшебства, кроме переписывания компилятором синтаксиса карты в вызовы функций в runtime/hmap.go.

И кое-что интересное об истории / объяснении mapсинтаксиса:

Если карты являются указателями, не так ли *map[key]value?

Хороший вопрос: если карты являются значениями указателей, почему выражение make(map[int]int)возвращает значение с типом map[int]int. Разве он не должен возвращать *map[int]int? Ян Тейлор недавно ответил на этот вопрос в треде 1 .

В самом начале то, что мы сейчас называем картами, писали как указатели, так что вы писали *map[int]int. Мы отошли от этого, когда поняли, что никто никогда не писал mapбез письма *map.

Возможно, переименование типа из *map[int]intв map[int]int, хотя и сбивало с толку, поскольку тип не выглядело как указатель, было менее запутанным, чем значение в форме указателя, которое нельзя разыменовать.

Акавалл
источник
1

Нет. Карты по умолчанию являются справочными.

    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 вызовут панику во время выполнения; не делай этого. Для инициализации карты используйте встроенную функцию make:

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

Ссылка на фрагмент кода Поиграйте с этим.

Аламин
источник