Как работает указатель на значение структуры или массива в Go? - PullRequest
0 голосов
/ 25 июня 2018

Учитывая следующую структуру Go:

type Person struct {
    Name    string
    Age     int
    Country string
}

Я неоднократно сталкивался со следующим использованием:

p := &Person{"Adam", 33, "Argentina"}

Пока я не вижу смысла указывать на значение структуры,и мне интересно, чем оно отличается от:

n := &999 // Error

Мои вопросы:

  1. Как вообще можно указать на значение, даже если оноструктура или массив, а не примитив, как строка или int?Как ни странно, следующее не способствует моему пониманию:

    fmt.Println(p, &p) // outputs: &{Adam 33 Argentina} 0xc042084018
    
  2. Почему программист хочет объявить экземпляр структуры указателем?Чего вы могли бы достичь, сделав это?

1 Ответ

0 голосов
/ 25 июня 2018

&Person{} является языковой «конструкцией», она является частью спецификации: она выделяет новую переменную типа Person и предоставляет вам адрес этой анонимной переменной.

Spec: Составные литералы:

При получении адреса составного литерала создается указатель на уникальную переменную , инициализированную значением литерала.

Также: Спецификация: Переменные:

Вызов встроенной функции new или с использованием адреса составного литерала выделяет память для переменной во время выполнения .

&999 не допускается языковой спецификацией. Возможные операнды операторов адреса перечислены в Spec: Операторы адреса:

Операнд должен быть адресуемым , то есть либо переменной, либо косвенным указателем, либо операцией индексации слайса; или селектор поля адресуемого структурного операнда; или операция индексации массива адресуемого массива. В качестве исключения из требования адресуемости, x также может быть (возможно заключенным в скобки) составным литералом .

p := Person{} создает новую переменную p, тип которой будет Person. p := &Person{} создает новую переменную, тип которой будет *Person.

Просмотр возможного дубликата: Как мне сделать литерал * int64 в Go?

Когда вы печатаете значения с пакетом fmt, у него есть определенные правила для печати значений разных типов:

Для составных объектов элементы печатаются с использованием этих правил, рекурсивно, расположенных следующим образом:

struct:             {field0 field1 ...}
array, slice:       [elem0 elem1 ...]
maps:               map[key1:value1 key2:value2]
pointer to above:   &{}, &[], &map[]

Когда вы используете fmt.Println(), будут применяться правила форматирования по умолчанию, которые для значения типа *int являются глаголом %p, который будет печатать адрес памяти в шестнадцатеричном формате, но для указателя на структуру он печатает значение структуры с добавлением знака & (&{}). Вы можете прочитать больше об этом в связанном вопросе: Разница между указателями Голанга

Если вы хотите напечатать указанное значение, разыменуйте указатель и передайте указанное значение, например ::

.
var p = new(int)
*p = 12
fmt.Println(*p) // Prints 12

Относительно того, почему нужно создать указатель на значение (а не значение), см. Следующие связанные вопросы:

Указатели против значений в параметрах и возвращаемых значениях

Зачем конструктору обратный адрес Go?

Go, X не реализует Y (... у метода есть указатель на приемник)

...