Бесплатный курс по Go. Зарегистрируйтесь для отслеживания прогресса →

Go: Аргументы с указателем

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

package main

import (
    "fmt"
)

type User struct {
    email    string
    password string
}

// при объявлении указываем,
// что переменная должна быть указателем.
// Для этого ставим звездочку * перед типом данных
func fillUserData(u *User, email string, pass string) {
    u.email = email
    u.password = pass
}

func main() {
    u := User{}

    // передаем указатель с помощью амперсанда
    // & перед переменной
    fillUserData(&u, "test@test.com", "qwerty")

    fmt.Printf("points on func call %+v\n", u)
    // points on func call {email:test@test.com password:qwerty}

    // сразу инициализируем переменную с указателем
    up := &User{}

    fillUserData(up, "test@test.com", "qwerty")

    fmt.Printf("points on init %+v\n", up)
    // points on init {email:test@test.com password:qwerty}
}

Мапы по умолчанию передаются с указателем:

package main

import (
    "fmt"
)

func main() {
    m := map[string]int{}

    fillMap(m)

    fmt.Println(m) // map[random:1]
}

func fillMap(m map[string]int) {
    m["random"] = 1
}

Разработчики, пришедшие из других языков, часто используют фразы "передача по ссылке" или "ссылка на переменную". Строго говоря, в Go нет ссылок, только указатели:

package main

import "fmt"

func main() {
    a := 1
    b := &a
    c := &b

    fmt.Printf("%p %p %p\n", &a, &b, &c)
    // 0xc000018030 0xc00000e028 0xc00000e030
}

В этом примере b и c содержат одинаковые значения — адрес переменной a, однако b и c хранятся в разных адресах. Из-за этого обновление переменной b не изменит c. Поэтому если кто-то говорит про ссылки в Go, он имеет в виду указатели.

Задание

Реализуйте функцию CopyParent(p *Parent) Parent, которая создает копию структуры Parent и возвращает ее:

type Parent struct {
    Name     string
    Children []Child
}

type Child struct {
    Name string
    Age  int
}

cp := CopyParent(nil) // Parent{}

p := &Parent{
   Name: "Harry",
   Children: []Child{
       {
           Name: "Andy",
           Age:  18,
       },
   },
}
cp := CopyParent(p)

// при мутациях в копии "cp"
// изначальная структура "p" не изменяется
cp.Children[0] = Child{}
fmt.Println(p.Children) // [{Andy 18}]
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

Полезное


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics
Если вы столкнулись с трудностями и не знаете, что делать, задайте вопрос в нашем большом и дружном сообществе