Когда параметром формы в go является map, что передается в? - PullRequest
0 голосов
/ 22 мая 2019

Когда формальным параметром является map, назначение значения непосредственно формальному параметру не может изменить фактический аргумент, но если вы добавите новый ключ и значение к формальному параметру, фактический аргумент за пределами функции также может быть виден.Почему это так?

Я не понимаю выходное значение следующего кода, и формальные параметры отличаются от фактических параметров.

unc main() {
    t := map[int]int{
        1: 1,
    }
    fmt.Println(unsafe.Pointer(&t))
    copysss(t)
    fmt.Println(t)
}
func copysss(m map[int]int) {
    //pointer := unsafe.Pointer(&m)
    //fmt.Println(pointer)
    m = map[int]int{
        1: 2,
    }
}
stdout :0xc000086010

        map[1:1]
func main() {
    t := map[int]int{
        1: 1,
    }
    fmt.Println(unsafe.Pointer(&t))
    copysss(t)
    fmt.Println(t)
}
func copysss(m map[int]int) {
    //pointer := unsafe.Pointer(&m)
    //fmt.Println(pointer)
    m[1] = 2
}
stdout :0xc00007a010

        map[1:2]
func main() {
    t := map[int]int{
        1: 1,
    }
    fmt.Println(unsafe.Pointer(&t))
    copysss(t)
    fmt.Println(t)
}
func copysss(m map[int]int) {
    pointer := unsafe.Pointer(&m)
    fmt.Println(pointer)
    m[1] = 2
}
stdout:0xc00008a008
       0xc00008a018
       map[1:2]

Я хочу знать, является ли параметр значением или указателем.

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

Параметр , значение и указатель.

Подождите .. что?

Да, карта (и, если на то пошло, фрагменты) - это типы, очень похожие на то, что вы бы реализовали. Думайте о карте так:

type map struct {
    // meta information on the map
    meta struct{
        keyT   type
        valueT type
        len    int
    }
    value *hashTable // pointer to the underlying data structure
}

Итак, в вашей первой функции, где вы переназначаете m, вы передаете копию структуры выше (передача по значению) и назначаете ей новую карту, создавая новый указатель хеш-таблицы в процессе. Переменная в области действия функции обновляется, но переданная вами по-прежнему содержит ссылку на исходную карту, а вместе с ней указатель на исходную карту сохраняется.

Во втором фрагменте вы получаете доступ к базовой хэш-таблице (копия указателя, но указатель указывает на ту же память). Вы напрямую манипулируете исходной картой, потому что вы просто меняете содержимое памяти.

Так TL; DR

Карта - это значение, содержащее метаинформацию о том, как карта выглядит, и указатель на фактические данные, хранящиеся внутри. Указатель передается по значению, как и все остальное (аналогично тому, как указатели передаются по значению в C / C ++), но, конечно, разыменование указателя означает, что вы изменяете значения в памяти напрямую.

Тщательное ... * * 1023 Как я уже сказал, срезы работают примерно так же: type slice struct { meta struct { type T len, cap int } value *array // yes, it's a pointer to an underlying array } Базовый массив, скажем, срез целых будет равен [10]int, если cap среза равен 10, независимо от длины. Срез управляется средой выполнения go, поэтому, если вы превышаете емкость, выделяется новый массив (вдвое больше cap предыдущего), существующие данные копируются, а поле slice value устанавливается на указать на новый массив. По этой причине append возвращает фрагмент, к которому вы добавляете, возможно, изменился базовый указатель и т. Д. Вы можете найти более подробную информацию по этому вопросу. Вы должны быть осторожны с такой функцией: func update(s []int) { for i, v := range s { s[i] = v*2 } } будет вести себя так же, как и функция, которую вы назначаете m[1] = 2, но как только вы начнете добавлять, среда выполнения сможет свободно перемещать базовый массив и указывать на новый адрес памяти. Итак, суть: карты и фрагменты имеют внутренний указатель, который может вызывать побочные эффекты, но лучше избегать ошибок / неясностей. Go поддерживает несколько возвращаемых значений, поэтому просто верните фрагмент, если вы решите изменить его. Примечания: В вашей попытке выяснить, что такое карта (ссылка, значение, указатель ...), я заметил, что вы попробовали это: pointer := unsafe.Pointer(&m) fmt.Println(pointer) То, что вы там делаете, на самом деле печатает адрес аргумента переменной , а не любой адрес, который на самом деле соответствует самой карте. аргумент, переданный unsafe.Pointer, не относится к типу map[int]int, а скорее к типу *map[int]int. Лично я думаю, что слишком много путаницы в отношении передачи по значению против передачи мимо. В этом отношении Go работает точно так же, как C, точно так же, как C, абсолютно все передается по значению. Так уж получилось, что это значение иногда может быть адресом памяти (указателем). Подробнее (ссылки) Ломтики: использование и внутреннее оборудование Карты Примечание: эта путаница вызвана некоторой путаницей, так как указатели, фрагменты и карты называются * ссылочными типами *, но, как объясняют другие, и в других местах это не путать со ссылками на C ++

0 голосов
/ 22 мая 2019

В Go карта является ссылочным типом.Это означает, что карта фактически находится в куче, а переменная является просто указателем на это.

Карта передается копией.Вы можете изменить локальную копию в своей функции, но это не будет отражено в области действия вызывающего.

Но, поскольку переменная карты является указателем на уникальную карту, находящуюся в куче, каждое изменение можно увидеть по любой переменной, которая указывает на ту же карту.

Эта статья может прояснить концепцию: https://www.ardanlabs.com/blog/2014/12/using-pointers-in-go.html.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...