Это пятая часть серии «Начало работы с Go». Если вы хотите ознакомиться с частями 1–4, вы можете найти их здесь:

  1. Часть 1: Привет, мир
  2. Часть 2: переменные и константы
  3. Часть 3: Функции
  4. Часть 4: Массивы и срезы
  5. Часть 5: Указатели и структуры (сейчас вы здесь)

На данный момент мы еще не упомянули указатели, и, если вы следили за нами, мы создали одну или две структуры на лету, но мы никогда не вдавались в подробности о них. Теперь давайте подробно рассмотрим оба из них, начиная с указателей. Я признаю, что, придя из Android, где указателей не существовало в Java или Kotlin, мне потребовалось некоторое время, чтобы понять, что такое указатели. Поэтому, прежде чем мы поговорим об указателях, я думаю, было бы полезно объяснить, как работает память в отношении хранения данных.

Память и данные

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

Всякий раз, когда мы создаем переменную и присваиваем ей некоторые данные следующим образом:

мы говорим компилятору сохранить число 6 в одном из этих желтых блоков памяти. Мы также назвали желтый кирпич «а», поэтому:

будет выглядеть так:

Теперь давайте посмотрим, где указатели входят в уравнение.

указатели

Поскольку у каждого кирпича на дороге из желтого кирпича есть собственный адрес, подобно домам на улице, мы можем присвоить эти адреса другой переменной. Не фактические данные, а адрес данных. Мы можем указать на этот адрес, поместив & перед переменной следующим образом:

Если мы хотим получить доступ к тому, что находится внутри a из b, мы должны поставить * перед b, это называется разыменованием.

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

type TinMan struct { 
    Heart string 
} 
func main() { 
     t := TinMan{ Heart: "Tin man has no heart." }
     fmt.Println(t.Heart) GetHeart(&t) fmt.Println(t.Heart) 
} 
func GetHeart(tinMan *TinMan) { 
    tinMain = "Tin man has a heart!" 
}

Если TinMan не будет передан в GetHeart как указатель, у TinMan никогда не будет сердца :(. Теперь мы должны быть знакомы с тем, как работают указатели, давайте поговорим о структурах.

Структуры

Проще говоря, структуры — это версия объектов в Go. Они в основном используются для объединения набора относительных полей в одном месте, мы хорошо начали с нашей версии TinMan.

type TinMan struct { 
    Heart string 
    Name string 
    NeedOil bool 
    Age int 
    PlacesTraveled []string 
}

У нашего TinMan теперь немного больше данных. В части 3 этой серии блогов мы рассмотрели функции, у которых есть приемник. Если вы случайно не прочитали эту статью, приемники — это способ гарантировать, что определенные функции могут быть вызваны только соответствующей структурой.

func (t *TinMan) TravelToDestination(destination string) { 
    if destination != "" { 
      t.PlacesTraveled = append(t.PlacesTraveled, destination) 
    } 
}

В приведенном выше примере мы настроили приемник TinMan для нашей функции TravelToDestination. Это простая функция, которая добавит пункт назначения в слайс PlacesTraveled, если пункт назначения не является пустой строкой. Кроме того, тип получателя должен быть указателем на структуру TinMan.

type TinMan struct { 
    Heart string 
    Name string 
    NeedOil bool 
    Age int 
    PlacesTraveled []string 
} 
func (t *TinMan) TravelToDestination(destination string) { 
    if destination != "" { 
      t.PlacesTraveled = append(t.PlacesTraveled, destination) 
    } 
} 
func main() { 
    t := TinMan{ 
        Heart: "heart", 
        Name: "Ed", 
        NeedOil: false, 
        Age: 13, 
        PlacesTraveled: []string{}, 
    } 
    
    t.TravelToDestination("here") 
    t.TravelToDestination("there")
    t.TravelToDestination("everywhere") 
    for i, _ := range t.PlacesTraveled { 
        fmt.Println("destination", i, t.PlacesTraveled[i]) 
    } 
}

Если мы соберем все вместе и запустим основную функцию, мы увидим следующее «здесь», «там» и «везде» в консоли. Однако, если бы мы сделали приемник для TravelToDestination обычной структурой TinMan, ничего не распечатывалось бы.

В этом сообщении блога мы кратко напомнили, как работает память в отношении хранения переменных вместе с указателями и структурами в Go. Как всегда приветствуется обратная связь! Надеюсь, этот пост был вам полезен :).

Первоначально опубликовано на https://justanother.dev 6 февраля 2020 г.