From a7a2a6473ef1ade6982bc4e86e8efe66b6f13ceb Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Tue, 18 Aug 2015 11:31:51 +0200 Subject: [PATCH] 02.4 --- ru/02.4.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++ ru/preface.md | 4 +- 2 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 ru/02.4.md diff --git a/ru/02.4.md b/ru/02.4.md new file mode 100644 index 0000000..4d6d34f --- /dev/null +++ b/ru/02.4.md @@ -0,0 +1,214 @@ +# 2.4 Структуры + +## struct + +В Go мы можем определять новые типы контейнеров свойств или полей так же, как и в других языках программирования. Например, чтобы описать личность, мы можем создать тип `person`с полями "имя" и "возраст". Мы назовем этот тип `структурой(struct)`: + + type person struct { + name string + age int + } + +Смотрите, как легко определять `структуру`! + +У нас есть два поля: + +- `name` - `string`, используется для того, чтобы хранить имя человека. +- `age` - `int`, используется для того, чтобы хранить возраст человека. + +Давайте посмотрим, как это использовать: + + type person struct { + name string + age int + } + + var P person // p - переменная типа person + + P.name = "Astaxie" // присваиваем "Astaxie" полю 'name' переменной p + P.age = 25 // присваиваем 25 полю 'age' переменной p + fmt.Printf("Имя человека - %s\n", P.name) // получаем значение поля 'name' переменной p + +Есть еще три способа определить `struct`: + +- Присвоить начальные значения по порядку: + + P := person{"Tom", 25} + +- Исопльзовать формат `поле:значение`, чтобы задать начальные значение структуры, при этом можно не соблюдать порядок, в котором поля шли при описании структуры: + + P := person{age:24, name:"Bob"} + +- Определить анонимную структуру, а затем задать ей значения: + + P := struct{name string; age int}{"Amy",18} + +Давайте рассмотрим конкретный пример: + + package main + import "fmt" + + // Определяем новый тип + type person struct { + name string + age int + } + + // сравниваем возраст у двух людей, затем возвращаем возраст старшего из них и разницу в возрасте + // струстуры передаются по значению + func Older(p1, p2 person) (person, int) { + if p1.age>p2.age { + return p1, p1.age-p2.age + } + return p2, p2.age-p1.age + } + + func main() { + var tom person + + // задаем первоначальные значения + tom.name, tom.age = "Tom", 18 + + // задаем значения в формате "поле:значение" + bob := person{age:25, name:"Bob"} + + // задаем значения в порядке, указанном при определении структуры + paul := person{"Paul", 43} + + tb_Older, tb_diff := Older(tom, bob) + tp_Older, tp_diff := Older(tom, paul) + bp_Older, bp_diff := Older(bob, paul) + + fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, bob.name, tb_Older.name, tb_diff) + + fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, paul.name, tp_Older.name, tp_diff) + + fmt.Printf("Из %s и %s %s старше на %d лет\n", bob.name, paul.name, bp_Older.name, bp_diff) + } + +### Встраиваемые поля в структуре + +Я только что показал Вам как определять структуру с именами и типами полей. Но Go поддерживает и поля с типами, но без имен. Мы называем это встраиваемыми полями. + +Когда встраиваемое поле - структура, все поля этой структуры неявно становятся полями структуры, в которую оно встроено. + +Посмторим на пример: + + package main + import "fmt" + + type Human struct { + name string + age int + weight int + } + + type Student struct { + Human // встраиваемое поле; это означает, что структура Student включает в себя все поля структуры Human. + specialty string + } + + func main() { + // инициализируем студента + mark := Student{Human{"Марк", 25, 120}, "Компьютерные науки"} + + // получаем доступ к полям + fmt.Println("Его имя: ", mark.name) + fmt.Println("Его возраст: ", mark.age) + fmt.Println("Его масса: ", mark.weight) + fmt.Println("Его специализация: ", mark.specialty) + // изменяем значения полей + mark.specialty = "Искусственный интеллект" + fmt.Println("Марк поменял специализацию") + fmt.Println("Его специализация: ", mark.specialty) + // изменяем возраст + fmt.Println("Марк постарел") + mark.age = 46 + fmt.Println("Его возраст: ", mark.age) + // изменияем массу + fmt.Println("Марк больше не атлет") + mark.weight += 60 + fmt.Println("Его масса: ", mark.weight) + } + +![](images/2.4.student_struct.png?raw=true) + +Рисунок 2.7 Наследование в Student и Human + +Мы видим, что можно иметь доступ к значениям полей Student так же, как и к Human. Так работают встраиваемые поля. Очень круто, не так ли? Держитесь, есть кое-что покруче! Вы можете использовать Student, чтобы получить доступ к Human в этом встраиваемом поле! + + mark.Human = Human{"Маркус", 55, 220} + mark.Human.age -= 1 + +Все тиы данных в Go могут использованы в качестве встраиваемых полей: + + package main + import "fmt" + + type Skills []string + + type Human struct { + name string + age int + weight int + } + + type Student struct { + Human // struct как встраиваемое поле + Skills // срез из строк как встраиваемое поле + int // встроенный тип как встраиваемое поле + specialty string + } + + func main() { + // Инициализируем студента Джейн + jane := Student{Human:Human{"Джейн", 35, 100}, specialty:"Биология"} + // доступ к полям + fmt.Println("Ее имя: ", jane.name) + fmt.Println("Ее возраст: ", jane.age) + fmt.Println("Ее масса: ", jane.weight) + fmt.Println("Ее специализация: ", jane.specialty) + // изменяем поле навыков + jane.Skills = []string{"анатомия"} + fmt.Println("Ее навыки: ", jane.Skills) + fmt.Println("Она овладела еще двумя навыками: ") + jane.Skills = append(jane.Skills, "физика", "golang") + fmt.Println("Теперь ее навыки: ", jane.Skills) + // изменяем встраиваемое поле + jane.int = 3 + fmt.Println("Ее любимое число: ", jane.int) + } + +В примере выше мы можем видеть, что данные всех типов могут быть встраиваемыми полями, и мы можем исопльзовать функции, чтобы оперировать ими. + +Есть, впрочем, одна проблема. Если у Human есть поле под названием `phone`, а у Student тоже есть поле с таким именем, как нам быть? + +В Go есть простой способ решить эту задачу. Внешние поля имеют уровень доступа выше, что означает, что, обращаясь к `student.phone`, мы оперируем с полем phone в student,а не в Human. Это свойство проще представить как `перегрузку` полей. + + package main + import "fmt" + + type Human struct { + name string + age int + phone string // у Human есть поле phone + } + + type Employee struct { + Human // встраиваемое поле Human + specialty string + phone string // у Employee также появляется поле phone + } + + func main() { + Bob := Employee{Human{"Боб", 34, "777-444-XXXX"}, "Дизайнер", "333-222"} + fmt.Println("Рабочий телефон Боба:", Bob.phone) + // оперируем с поле phone в Human + fmt.Println("Личный телефон Боба:", Bob.Human.phone) + } + +## Ссылки + +- [Содержание](preface.md) +- Предыдущий раздел: [Управляющие конструкции и функции](02.3.md) +- Следующий раздел: [Объектно-ориентированные программирование](02.5.md) diff --git a/ru/preface.md b/ru/preface.md index cec43ef..7ee615c 100644 --- a/ru/preface.md +++ b/ru/preface.md @@ -8,8 +8,8 @@ - 2.1. ["Hello, Go"](02.1.md) - 2.2. [Фундамент Go](02.2.md) - 2.3. [Управляющие конструкции и функции](02.3.md) - - 2.4. [struct](02.4.md) - - 2.5. [Object-oriented](02.5.md) + - 2.4. [Структуры](02.4.md) + - 2.5. [Объектно-ориентированное программирование](02.5.md) - 2.6. [interface](02.6.md) - 2.7. [Concurrency](02.7.md) - 2.8. [Summary](02.8.md) -- GitLab