Карти передаються за значенням або за посиланням у Go?


90

Чи передаються карти за значенням або посиланням у Go?

Завжди можна визначити функцію наступною, але чи це надмірне?

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

Те саме питання щодо поверненого значення. Чи слід повертати вказівник на карту або повертати карту як значення?

Намір, звичайно, уникнути непотрібного копіювання даних.


4
blog.golang.org/go-maps-in-action : Типи карт є посилальними типами, як покажчики або фрагменти, і тому значення m вище дорівнює нулю; це не вказує на ініціалізовану карту. Карта nil під час читання поводиться як порожня карта, але спроби записати на карту nil викликають паніку в процесі виконання; не роби цього. Для ініціалізації карти використовуйте вбудовану функцію make
mh-cbon

2
Все в Go передається за значенням. Деякі значення бувають покажчиками або структурами, що містять покажчики. (можливо, вам знадобиться a *map, якщо вам потрібно перепризначити значення карти за адресою)
JimB

mh-cbon, в Go немає посилальних типів.
Інанк Гумус,

@ mh-cbon Я не говорив про еталонний тип. Я запитував, чи передається карта за посиланням, що еквівалентно запиту, передається ли адреса карти як аргумент або "копія" карти (передається за значенням).
chmike

1
@ mh-cbon Точно, карти є вказівниками на hmap.
Інанк Гумус,

Відповіді:


80

У цій темі ви знайдете свою відповідь:

Голанг: Доступ до карти за допомогою її посилання

Вам не потрібно використовувати вказівник з картою.

Типи карт є еталонними типами, як покажчики або фрагменти [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. Чи не повинно повернути a *map[int]int? Ян Тейлор відповів на цей питання в останній час в golang гайки різьблення 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)

Код фрагмента посилання Пограйте з ним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.