|
3 | 3 | ## struct
|
4 | 4 |
|
5 | 5 | В Go мы можем определять новые типы контейнеров свойств или полей так же, как и в других языках программирования. Например, чтобы описать личность, мы можем создать тип `person`с полями "имя" и "возраст". Мы назовем этот тип `структурой(struct)`:
|
6 |
| - |
7 |
| - type person struct { |
8 |
| - name string |
9 |
| - age int |
10 |
| - } |
11 |
| - |
| 6 | +```Go |
| 7 | +type person struct { |
| 8 | + name string |
| 9 | + age int |
| 10 | +} |
| 11 | +``` |
12 | 12 | Вот так как легко определять `структуру`!
|
13 | 13 |
|
14 | 14 | У нас есть два поля:
|
|
17 | 17 | - `age` - `int`, используется для того, чтобы хранить возраст человека.
|
18 | 18 |
|
19 | 19 | Давайте посмотрим, как это использовать:
|
20 |
| - |
21 |
| - type person struct { |
22 |
| - name string |
23 |
| - age int |
24 |
| - } |
25 |
| - |
26 |
| - var P person // p - переменная типа person |
27 |
| - |
28 |
| - P.name = "Astaxie" // присваиваем "Astaxie" полю 'name' переменной p |
29 |
| - P.age = 25 // присваиваем 25 полю 'age' переменной p |
30 |
| - fmt.Printf("Имя человека - %s\n", P.name) // получаем значение поля 'name' переменной p |
31 |
| - |
| 20 | +```Go |
| 21 | +type person struct { |
| 22 | + name string |
| 23 | + age int |
| 24 | +} |
| 25 | + |
| 26 | +var P person // p - переменная типа person |
| 27 | + |
| 28 | +P.name = "Astaxie" // присваиваем "Astaxie" полю 'name' переменной p |
| 29 | +P.age = 25 // присваиваем 25 полю 'age' переменной p |
| 30 | +fmt.Printf("Имя человека - %s\n", P.name) // получаем значение поля 'name' переменной p |
| 31 | +``` |
32 | 32 | Есть еще три способа определить `struct`:
|
33 | 33 |
|
34 | 34 | - Присвоить начальные значения по порядку:
|
35 |
| - |
36 |
| - P := person{"Tom", 25} |
37 |
| - |
| 35 | +```Go |
| 36 | +P := person{"Tom", 25} |
| 37 | +``` |
38 | 38 | - Использовать формат `поле:значение`, чтобы задать начальные значения полей структуры, при этом можно не соблюдать порядок, в котором поля шли при описании структуры:
|
39 |
| - |
40 |
| - P := person{age:24, name:"Bob"} |
41 |
| - |
| 39 | +```Go |
| 40 | +P := person{age: 24, name: "Bob"} |
| 41 | +``` |
42 | 42 | - Определить анонимную структуру, а затем задать ей значения:
|
43 |
| - |
44 |
| - P := struct{name string; age int}{"Amy",18} |
45 |
| - |
| 43 | +```Go |
| 44 | +P := struct{name string; age int}{"Amy", 18} |
| 45 | +``` |
46 | 46 | Давайте рассмотрим конкретный пример:
|
| 47 | +```Go |
| 48 | +package main |
| 49 | +import "fmt" |
47 | 50 |
|
48 |
| - package main |
49 |
| - import "fmt" |
| 51 | +// Определяем новый тип |
| 52 | +type person struct { |
| 53 | + name string |
| 54 | + age int |
| 55 | +} |
50 | 56 |
|
51 |
| - // Определяем новый тип |
52 |
| - type person struct { |
53 |
| - name string |
54 |
| - age int |
55 |
| - } |
| 57 | +// сравниваем возраст у двух людей, затем возвращаем возраст старшего из них и разницу в возрасте. |
| 58 | +// структуры передаются по значению |
| 59 | +func Older(p1, p2 person) (person, int) { |
| 60 | + if p1.age > p2.age { |
| 61 | + return p1, p1.age - p2.age |
| 62 | + } |
| 63 | + return p2, p2.age - p1.age |
| 64 | +} |
56 | 65 |
|
57 |
| - // сравниваем возраст у двух людей, затем возвращаем возраст старшего из них и разницу в возрасте. |
58 |
| - // структуры передаются по значению |
59 |
| - func Older(p1, p2 person) (person, int) { |
60 |
| - if p1.age>p2.age { |
61 |
| - return p1, p1.age-p2.age |
62 |
| - } |
63 |
| - return p2, p2.age-p1.age |
64 |
| - } |
| 66 | +func main() { |
| 67 | + var tom person |
65 | 68 |
|
66 |
| - func main() { |
67 |
| - var tom person |
| 69 | + // задаем первоначальные значения |
| 70 | + tom.name, tom.age = "Tom", 18 |
68 | 71 |
|
69 |
| - // задаем первоначальные значения |
70 |
| - tom.name, tom.age = "Tom", 18 |
| 72 | + // задаем значения в формате "поле:значение" |
| 73 | + bob := person{age: 25, name: "Bob"} |
71 | 74 |
|
72 |
| - // задаем значения в формате "поле:значение" |
73 |
| - bob := person{age:25, name:"Bob"} |
| 75 | + // задаем значения в порядке, указанном при определении структуры |
| 76 | + paul := person{"Paul", 43} |
74 | 77 |
|
75 |
| - // задаем значения в порядке, указанном при определении структуры |
76 |
| - paul := person{"Paul", 43} |
| 78 | + tb_Older, tb_diff := Older(tom, bob) |
| 79 | + tp_Older, tp_diff := Older(tom, paul) |
| 80 | + bp_Older, bp_diff := Older(bob, paul) |
77 | 81 |
|
78 |
| - tb_Older, tb_diff := Older(tom, bob) |
79 |
| - tp_Older, tp_diff := Older(tom, paul) |
80 |
| - bp_Older, bp_diff := Older(bob, paul) |
| 82 | + fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, bob.name, tb_Older.name, tb_diff) |
81 | 83 |
|
82 |
| - fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, bob.name, tb_Older.name, tb_diff) |
| 84 | + fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, paul.name, tp_Older.name, tp_diff) |
83 | 85 |
|
84 |
| - fmt.Printf("Из %s и %s %s старше на %d лет\n", tom.name, paul.name, tp_Older.name, tp_diff) |
85 |
| - |
86 |
| - fmt.Printf("Из %s и %s %s старше на %d лет\n", bob.name, paul.name, bp_Older.name, bp_diff) |
87 |
| - } |
88 |
| - |
| 86 | + fmt.Printf("Из %s и %s %s старше на %d лет\n", bob.name, paul.name, bp_Older.name, bp_diff) |
| 87 | +} |
| 88 | +``` |
89 | 89 | ### Встраиваемые поля в структуре
|
90 | 90 |
|
91 | 91 | Я только что показал Вам, как определять структуру с именами и типами полей. Но Go поддерживает и поля с типами, но без имен. Мы называем это встраиваемыми полями.
|
92 | 92 |
|
93 | 93 | Когда встраиваемое поле - структура, все поля этой структуры неявно становятся полями структуры, в которую оно встроено.
|
94 | 94 |
|
95 | 95 | Посмотрим на пример:
|
| 96 | +```Go |
| 97 | +package main |
| 98 | +import "fmt" |
96 | 99 |
|
97 |
| - package main |
98 |
| - import "fmt" |
99 |
| - |
100 |
| - type Human struct { |
101 |
| - name string |
102 |
| - age int |
103 |
| - weight int |
104 |
| - } |
| 100 | +type Human struct { |
| 101 | + name string |
| 102 | + age int |
| 103 | + weight int |
| 104 | +} |
105 | 105 |
|
106 |
| - type Student struct { |
| 106 | +type Student struct { |
107 | 107 | Human // встраиваемое поле; это означает, что структура Student включает в себя все поля структуры Human.
|
108 | 108 | specialty string
|
109 |
| - } |
110 |
| - |
111 |
| - func main() { |
112 |
| - // инициализируем студента |
113 |
| - mark := Student{Human{"Марк", 25, 120}, "Компьютерные науки"} |
114 |
| - |
115 |
| - // получаем доступ к полям |
116 |
| - fmt.Println("Его имя: ", mark.name) |
117 |
| - fmt.Println("Его возраст: ", mark.age) |
118 |
| - fmt.Println("Его масса: ", mark.weight) |
119 |
| - fmt.Println("Его специализация: ", mark.specialty) |
120 |
| - // изменяем значения полей |
121 |
| - mark.specialty = "Искусственный интеллект" |
122 |
| - fmt.Println("Марк поменял специализацию") |
123 |
| - fmt.Println("Его специализация: ", mark.specialty) |
124 |
| - // изменяем возраст |
125 |
| - fmt.Println("Марк постарел") |
126 |
| - mark.age = 46 |
127 |
| - fmt.Println("Его возраст: ", mark.age) |
128 |
| - // изменяем массу |
129 |
| - fmt.Println("Марк больше не атлет") |
130 |
| - mark.weight += 60 |
131 |
| - fmt.Println("Его масса: ", mark.weight) |
132 |
| - } |
133 |
| - |
| 109 | +} |
| 110 | + |
| 111 | +func main() { |
| 112 | + // инициализируем студента |
| 113 | + mark := Student{Human{"Марк", 25, 120}, "Компьютерные науки"} |
| 114 | + |
| 115 | + // получаем доступ к полям |
| 116 | + fmt.Println("Его имя: ", mark.name) |
| 117 | + fmt.Println("Его возраст: ", mark.age) |
| 118 | + fmt.Println("Его масса: ", mark.weight) |
| 119 | + fmt.Println("Его специализация: ", mark.specialty) |
| 120 | + // изменяем значения полей |
| 121 | + mark.specialty = "Искусственный интеллект" |
| 122 | + fmt.Println("Марк поменял специализацию") |
| 123 | + fmt.Println("Его специализация: ", mark.specialty) |
| 124 | + // изменяем возраст |
| 125 | + fmt.Println("Марк постарел") |
| 126 | + mark.age = 46 |
| 127 | + fmt.Println("Его возраст: ", mark.age) |
| 128 | + // изменяем массу |
| 129 | + fmt.Println("Марк больше не атлет") |
| 130 | + mark.weight += 60 |
| 131 | + fmt.Println("Его масса: ", mark.weight) |
| 132 | +} |
| 133 | +``` |
134 | 134 | 
|
135 | 135 |
|
136 | 136 | Рисунок 2.7 Наследование в Student и Human
|
137 | 137 |
|
138 | 138 | Мы видим, что можно иметь доступ к значениям полей Student так же, как и к Human. Так работают встраиваемые поля. Очень круто, не так ли? Держитесь, есть кое-что покруче! Вы можете использовать Student, чтобы получить доступ к Human в этом встраиваемом поле!
|
139 |
| - |
140 |
| - mark.Human = Human{"Маркус", 55, 220} |
141 |
| - mark.Human.age -= 1 |
142 |
| - |
143 |
| -Все тиы данных в Go могут использованы в качестве встраиваемых полей: |
144 |
| - |
145 |
| - package main |
146 |
| - import "fmt" |
147 |
| - |
148 |
| - type Skills []string |
149 |
| - |
150 |
| - type Human struct { |
151 |
| - name string |
152 |
| - age int |
153 |
| - weight int |
154 |
| - } |
155 |
| - |
156 |
| - type Student struct { |
157 |
| - Human // struct как встраиваемое поле |
158 |
| - Skills // срез из строк как встраиваемое поле |
159 |
| - int // встроенный тип как встраиваемое поле |
160 |
| - specialty string |
161 |
| - } |
162 |
| - |
163 |
| - func main() { |
164 |
| - // Инициализируем студента Джейн |
165 |
| - jane := Student{Human:Human{"Джейн", 35, 100}, specialty:"Биология"} |
166 |
| - // доступ к полям |
167 |
| - fmt.Println("Ее имя: ", jane.name) |
168 |
| - fmt.Println("Ее возраст: ", jane.age) |
169 |
| - fmt.Println("Ее масса: ", jane.weight) |
170 |
| - fmt.Println("Ее специализация: ", jane.specialty) |
171 |
| - // изменяем поле навыков |
172 |
| - jane.Skills = []string{"анатомия"} |
173 |
| - fmt.Println("Ее навыки: ", jane.Skills) |
174 |
| - fmt.Println("Она овладела еще двумя навыками: ") |
175 |
| - jane.Skills = append(jane.Skills, "физика", "golang") |
176 |
| - fmt.Println("Теперь ее навыки: ", jane.Skills) |
177 |
| - // изменяем встраиваемое поле |
178 |
| - jane.int = 3 |
179 |
| - fmt.Println("Ее любимое число: ", jane.int) |
180 |
| - } |
181 |
| - |
| 139 | +```Go |
| 140 | +mark.Human = Human{"Маркус", 55, 220} |
| 141 | +mark.Human.age -= 1 |
| 142 | +``` |
| 143 | +Все типы данных в Go могут быть использованы в качестве встраиваемых полей: |
| 144 | +```Go |
| 145 | +package main |
| 146 | +import "fmt" |
| 147 | + |
| 148 | +type Skills []string |
| 149 | + |
| 150 | +type Human struct { |
| 151 | + name string |
| 152 | + age int |
| 153 | + weight int |
| 154 | +} |
| 155 | + |
| 156 | +type Student struct { |
| 157 | + Human // struct как встраиваемое поле |
| 158 | + Skills // срез из строк как встраиваемое поле |
| 159 | + int // встроенный тип как встраиваемое поле |
| 160 | + specialty string |
| 161 | +} |
| 162 | + |
| 163 | +func main() { |
| 164 | + // Инициализируем студента Джейн |
| 165 | + jane := Student{Human:Human{"Джейн", 35, 100}, specialty:"Биология"} |
| 166 | + // доступ к полям |
| 167 | + fmt.Println("Ее имя: ", jane.name) |
| 168 | + fmt.Println("Ее возраст: ", jane.age) |
| 169 | + fmt.Println("Ее масса: ", jane.weight) |
| 170 | + fmt.Println("Ее специализация: ", jane.specialty) |
| 171 | + // изменяем поле навыков |
| 172 | + jane.Skills = []string{"анатомия"} |
| 173 | + fmt.Println("Ее навыки: ", jane.Skills) |
| 174 | + fmt.Println("Она овладела еще двумя навыками: ") |
| 175 | + jane.Skills = append(jane.Skills, "физика", "golang") |
| 176 | + fmt.Println("Теперь ее навыки: ", jane.Skills) |
| 177 | + // изменяем встраиваемое поле |
| 178 | + jane.int = 3 |
| 179 | + fmt.Println("Ее любимое число: ", jane.int) |
| 180 | +} |
| 181 | +``` |
182 | 182 | В примере выше мы можем видеть, что данные всех типов могут быть встраиваемыми полями, и мы можем использовать функции, чтобы оперировать ими.
|
183 | 183 |
|
184 | 184 | Есть, впрочем, одна проблема. Если у `Human` есть поле под названием `phone`, а у `Student` тоже есть поле с таким именем, как нам быть?
|
185 | 185 |
|
186 | 186 | В Go есть простой способ решить эту задачу. Внешние поля имеют уровень доступа выше, что означает, что, обращаясь к `student.phone`, мы оперируем с полем `phone` в `student`,а не в `Human`. Это свойство проще представить как `перегрузку` полей.
|
187 |
| - |
188 |
| - package main |
189 |
| - import "fmt" |
190 |
| - |
191 |
| - type Human struct { |
192 |
| - name string |
193 |
| - age int |
194 |
| - phone string // у Human есть поле phone |
195 |
| - } |
196 |
| - |
197 |
| - type Employee struct { |
198 |
| - Human // встраиваемое поле Human |
199 |
| - specialty string |
200 |
| - phone string // у Employee также появляется поле phone |
201 |
| - } |
202 |
| - |
203 |
| - func main() { |
204 |
| - Bob := Employee{Human{"Боб", 34, "777-444-XXXX"}, "Дизайнер", "333-222"} |
205 |
| - fmt.Println("Рабочий телефон Боба:", Bob.phone) |
206 |
| - // оперируем с поле phone в Human |
207 |
| - fmt.Println("Личный телефон Боба:", Bob.Human.phone) |
208 |
| - } |
209 |
| - |
| 187 | +```Go |
| 188 | +package main |
| 189 | +import "fmt" |
| 190 | + |
| 191 | +type Human struct { |
| 192 | + name string |
| 193 | + age int |
| 194 | + phone string // у Human есть поле phone |
| 195 | +} |
| 196 | + |
| 197 | +type Employee struct { |
| 198 | + Human // встраиваемое поле Human |
| 199 | + specialty string |
| 200 | + phone string // у Employee также появляется поле phone |
| 201 | +} |
| 202 | + |
| 203 | +func main() { |
| 204 | + Bob := Employee{Human{"Боб", 34, "777-444-XXXX"}, "Дизайнер", "333-222"} |
| 205 | + fmt.Println("Рабочий телефон Боба:", Bob.phone) |
| 206 | + // оперируем с поле phone в Human |
| 207 | + fmt.Println("Личный телефон Боба:", Bob.Human.phone) |
| 208 | +} |
| 209 | +``` |
210 | 210 | ## Ссылки
|
211 | 211 |
|
212 | 212 | - [Содержание](preface.md)
|
|
0 commit comments