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}]
Упражнение не проходит проверку — что делать? 😶

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

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

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

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

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

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

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

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

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

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются
Loading...

Ваше упражнение проверяется по этим тестам

1package solution
2
3import (
4	"github.com/stretchr/testify/assert"
5	"testing"
6)
7
8func TestCopyParent(t *testing.T) {
9	a := assert.New(t)
10
11	// nil case
12	cp := CopyParent(nil)
13	a.Equal(Parent{}, cp)
14
15	// filled struct case
16	p := &Parent{
17		Name: "Harry",
18		Children: []Child{
19			{
20				Name: "Andy",
21				Age:  18,
22			},
23			{
24				Name: "Vasya",
25				Age:  22,
26			},
27		},
28	}
29
30	cp = CopyParent(p)
31	cp.Children[0] = Child{}
32
33	a.Equal("Harry", cp.Name)
34	a.Equal("Harry", p.Name)
35	a.Len(p.Children, 2)
36	a.Len(cp.Children, 2)
37	a.Equal([]Child{
38		{
39			Name: "Andy",
40			Age:  18,
41		},
42		{
43			Name: "Vasya",
44			Age:  22,
45		},
46	}, p.Children)
47	a.Equal([]Child{
48		{},
49		{
50			Name: "Vasya",
51			Age:  22,
52		},
53	}, cp.Children)
54}
55

Решение учителя откроется через:

20:00
waiting_clock