Skip to content

Latest commit

 

History

History
214 lines (157 loc) · 9.18 KB

File metadata and controls

214 lines (157 loc) · 9.18 KB

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)
}

Рисунок 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)
}

Ссылки