02.5
This commit is contained in:
121
ru/02.5.md
121
ru/02.5.md
@@ -1,6 +1,5 @@
|
||||
# Объектно-ориентированное программирование
|
||||
|
||||
We talked about functions and structs in the last two sections, but did you ever consider using functions as fields of a struct? In this section, I will introduce you to another form of function that has a receiver, which is called `method`.
|
||||
В предыдущих двух разделах мы говорили о функциях и структурах, но рассматривали ли Вы когда-нибудь функции как поля структуры? В этом разделе я познакомлю Вас с еще одним видом функций, который называется "метод".
|
||||
|
||||
## Метод
|
||||
@@ -25,7 +24,7 @@ We talked about functions and structs in the last two sections, but did you ever
|
||||
fmt.Println("Площадь r2: ", area(r2))
|
||||
}
|
||||
|
||||
Этот код может вычислить площадь прямоугольника. Мы используем для этого функцию `area`, но это не метод структуры "rectangle" (как методы классов в классических объектно-ориентированных языках). Как Вы можете заметить, функция и структура здесь - две независимые друг от друга сущности.
|
||||
Этот код вычисляет площадь прямоугольника. Мы используем для этого функцию `area`, но это не метод структуры "rectangle" (как методы классов в классических объектно-ориентированных языках). Как Вы можете заметить, функция и структура здесь - две независимые друг от друга сущности.
|
||||
|
||||
Пока что это не является проблемой. однако, если Вам нужно будет посчитать также площади круга, квадрата, пятиугольника или другой геометрической фигуры, Вам придется добавлять новые фукнции с похожими именами.
|
||||
|
||||
@@ -35,7 +34,6 @@ We talked about functions and structs in the last two sections, but did you ever
|
||||
|
||||
Очевидно, что это не очень хорошо. Площадь должна быть свойством круга или прямоугольника.
|
||||
|
||||
For those reasons, we have the `method` concept. `method` is affiliated with type. It has the same syntax as functions do except for an additional parameter after the `func` keyword called the `receiver`, which is the main body of that method.
|
||||
По этой причине в Go есть концепция `метода`. `Метод` привязывается к типу данных. У него такой же синтаксис, как и у функции, за исключением дополнительного параметра, идущего после ключевого слова `func` и называемого `ресивер`, который является основным телом метода.
|
||||
|
||||
В этом же примере `Rectangle.area()` мог бы принадлежать непосредственно `rectangle`, а не являться внешней функцией. Еще точнее, `length`, `width` и `area()` все принадлежат `rectangle`.
|
||||
@@ -44,9 +42,9 @@ For those reasons, we have the `method` concept. `method` is affiliated with typ
|
||||
|
||||
"Метод - это функция, где первым указанным является аргумент, называемый ресивером."
|
||||
|
||||
Синтаксис метода.
|
||||
Синтаксис метода:
|
||||
|
||||
func (r ReceiverType) funcName(parameters) (results)
|
||||
func (r ТипРесивера) funcName(параметры) (результаты)
|
||||
|
||||
Давайте изменим наш пример, используя `методы`:
|
||||
|
||||
@@ -84,28 +82,27 @@ For those reasons, we have the `method` concept. `method` is affiliated with typ
|
||||
fmt.Println("Площадь c2: ", c2.area())
|
||||
}
|
||||
|
||||
Примечания относительно испоьлзования методов:
|
||||
Примечания относительно использования методов:
|
||||
|
||||
- Если у методов одинаковые имена, но они относятся к разным ресиверам - это разные методы.
|
||||
- Методы имеют доступ к полям внутри ресивера.
|
||||
- Use `.` to call a method in the struct, the same way fields are called.
|
||||
- Для того, чтобы вызвать метод структуры, используйте `.`, аналогично тому, как Вы работаете с полями.
|
||||
|
||||

|
||||
|
||||
Рисунок 2.9 Методы отличаются друг от друга, если принадлежат разным структурам
|
||||
|
||||
В указанном выше примере методы area() есть у структуры Rectangle и у Circle соответственно, поэтому ресиверами являются Rectangle и Circle.
|
||||
В указанном выше примере методы area() есть у структуры Rectangle и у Circle соответственно, поэтому ресиверами этих методов являются Rectangle и Circle.
|
||||
|
||||
One thing that's worth noting is that the method with a dotted line means the receiver is passed by value, not by reference. The difference between them is that a method can change its receiver's values when the receiver is passed by reference, and it gets a copy of the receiver when the receiver is passed by value.
|
||||
Стоит отметить, что метод с многоточием означает, что ресивер передается по значению, а не по ссылке. Различие в том, что когда ресивер передается по ссылке, метод может менять его значение, а когда ресивер передается по значению, метод работает с его копией.
|
||||
|
||||
Can the receiver only be a struct? Of course not. Any type can be the receiver of a method. You may be confused about customized types. Struct is a special kind of customized type -there are more customized types.
|
||||
Можем ли ресивер быть только лишь структурой? Конечно, нет. Ресивером может быть любой тип данных. Если у Вас возникла неясность в связи с типами, создаваемыми пользователями - структура является одним из них, но их может быть и больше.
|
||||
|
||||
Use the following format to define a customized type.
|
||||
Чтобы создать свой тип, используйте следующий формат:
|
||||
|
||||
type typeName typeLiteral
|
||||
|
||||
Examples of customized types:
|
||||
Примеры типов, созданных пользователем:
|
||||
|
||||
type ages int
|
||||
|
||||
@@ -114,17 +111,17 @@ Examples of customized types:
|
||||
type months map[string]int
|
||||
|
||||
m := months {
|
||||
"January":31,
|
||||
"February":28,
|
||||
"Январь":31,
|
||||
"Февраль":28,
|
||||
...
|
||||
"December":31,
|
||||
"Декабрь":31,
|
||||
}
|
||||
|
||||
I hope that you know how to use customized types now. Similar to `typedef` in C, we use `ages` to substitute `int` in the above example.
|
||||
Я надеюсь, теперь Вы поняли, как использовать такие типы. Так же, как `typedef` используется в C, в вышеприведенном примере можно использовать `ages` для замены `int`.
|
||||
|
||||
Let's get back to talking about `method`.
|
||||
Но давайте вернемся к `методам`.
|
||||
|
||||
You can use as many methods in custom types as you want.
|
||||
В созданных пользователем типах можно использовать столько методов, сколько захотите.
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
@@ -144,7 +141,7 @@ You can use as many methods in custom types as you want.
|
||||
color Color
|
||||
}
|
||||
|
||||
type BoxList []Box //a slice of boxes
|
||||
type BoxList []Box //срез, состоящий из элементов типа Box
|
||||
|
||||
func (b Box) Volume() float64 {
|
||||
return b.width * b.height * b.depth
|
||||
@@ -173,7 +170,7 @@ You can use as many methods in custom types as you want.
|
||||
}
|
||||
|
||||
func (c Color) String() string {
|
||||
strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
|
||||
strings := []string {"белый", "черный", "синий", "красный", "желтый"}
|
||||
return strings[c]
|
||||
}
|
||||
|
||||
@@ -187,47 +184,47 @@ You can use as many methods in custom types as you want.
|
||||
Box{20, 20, 20, YELLOW},
|
||||
}
|
||||
|
||||
fmt.Printf("We have %d boxes in our set\n", len(boxes))
|
||||
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
|
||||
fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
|
||||
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
|
||||
fmt.Printf("В наборе имеются %d коробок\n", len(boxes))
|
||||
fmt.Println("Объем первой из них равен ", boxes[0].Volume(), "cm³")
|
||||
fmt.Println("Цвет последней - ",boxes[len(boxes)-1].color.String())
|
||||
fmt.Println("Самая большая из них имеет цвет: ", boxes.BiggestsColor().String())
|
||||
|
||||
fmt.Println("Let's paint them all black")
|
||||
fmt.Println("Давайте покрасим их все в черный цвет")
|
||||
boxes.PaintItBlack()
|
||||
fmt.Println("The color of the second one is", boxes[1].color.String())
|
||||
fmt.Println("Цвет второй коробки - ", boxes[1].color.String())
|
||||
|
||||
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
|
||||
fmt.Println("Очевидно, что цвет самой большой коробки теперь ", boxes.BiggestsColor().String())
|
||||
}
|
||||
|
||||
We define some constants and customized types.
|
||||
Мы определили несколько констант и своих типов:
|
||||
|
||||
- Use `Color` as alias of `byte`.
|
||||
- Define a struct `Box` which has fields height, width, length and color.
|
||||
- Define a struct `BoxList` which has `Box` as its field.
|
||||
- Мы использовали `Color` как синоним `byte`.
|
||||
- Определили структуру `Box`, у которой есть поля height, width, length и color (высота, ширина, длина и цвет соответственно - прим.пер.).
|
||||
- Определили тип `BoxList`, содержащий элементы типа `Box`.
|
||||
|
||||
Then we defined some methods for our customized types.
|
||||
Затем мы определили методы для наших созданных типов:
|
||||
|
||||
- Volume() uses Box as its receiver and returns volume of Box.
|
||||
- SetColor(c Color) changes Box's color.
|
||||
- BiggestsColor() returns the color which has the biggest volume.
|
||||
- PaintItBlack() sets color for all Box in BoxList to black.
|
||||
- String() use Color as its receiver, returns the string format of color name.
|
||||
- Volume() использует Box как ресивер и возвращает объем Box.
|
||||
- SetColor(c Color) изменяет цвет Box.
|
||||
- BiggestsColor() возвращает цвет, который имеет наибольшее "значение".
|
||||
- PaintItBlack() устанавливает цвет всех коробок (Box) в BoxList как черный.
|
||||
- String() использует Color как ресивер и возвращает название цвета как строку.
|
||||
|
||||
Is it much clearer when we use words to describe our requirements? We often write our requirements before we start coding.
|
||||
Когда мы используем слова для того, чтобы описать свои потребности, все становится яснее. Мы часто записываем свои потребности перед тем, как начать писать код.
|
||||
|
||||
### Use pointer as receiver
|
||||
### Использование указателя в качестве ресивера
|
||||
|
||||
Let's take a look at `SetColor` method. Its receiver is a pointer of Box. Yes, you can use `*Box` as a receiver. Why do we use a pointer here? Because we want to change Box's color in this method. Thus, if we don't use a pointer, it will only change the value inside a copy of Box.
|
||||
Давайте посмотрим на метод `SetColor`. Его ресивером является указатель на Box. Да, можно использовать `*Box` в качесве ресивера. Почему мы использовали здесь указатель? Потому что в этом методе мы хотим изменить цвет коробки (Box). Если бы мы не использовали указатель, метод бы изменил цвет лишь у копии Box.
|
||||
|
||||
If we see that a receiver is the first argument of a method, it's not hard to understand how it works.
|
||||
Если мы видим, что ресивер - первый аргумент метода, несложно понять, как это работает.
|
||||
|
||||
You might be asking why we aren't using `(*b).Color=c` instead of `b.Color=c` in the SetColor() method. Either one is OK here because Go knows how to interpret the assignment. Do you think Go is more fascinating now?
|
||||
Вы можете спросить, почему мы не написали `(*b).Color=c` вместо `b.Color=c` в методе SetColor(). Но все в порядке, поскольку Go знает, как интерпретировать это выражение. Не правда ли, Go восхитителен?
|
||||
|
||||
You may also be asking whether we should use `(&bl[i]).SetColor(BLACK)` in `PaintItBlack` because we pass a pointer to `SetColor`. Again, either one is OK because Go knows how to interpret it!
|
||||
Вы также можете спросить, не должны ли мы использовать `(&bl[i]).SetColor(BLACK)` в `PaintItBlack`, ведь мы передаем в `SetColor` указатель. Опять же, и здесь все в порядке, поскольку Go знает, как интерпретировать и это!
|
||||
|
||||
### Inheritance of method
|
||||
### Наследование методов
|
||||
|
||||
We learned about inheritance of fields in the last section. Similarly, we also have method inheritance in Go. If an anonymous field has methods, then the struct that contains the field will have all the methods from it as well.
|
||||
В предыдущм разделе мы изучили наследование полей. Аналогично этому в Go мы можем наследовать методы. Если анонимное поле содержит методы, то структура, которая сожержит это поле, также располагает всеми методами этого поля:
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
@@ -239,7 +236,7 @@ We learned about inheritance of fields in the last section. Similarly, we also h
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
Human // anonymous field
|
||||
Human // анонимное поле
|
||||
school string
|
||||
}
|
||||
|
||||
@@ -248,22 +245,22 @@ We learned about inheritance of fields in the last section. Similarly, we also h
|
||||
company string
|
||||
}
|
||||
|
||||
// define a method in Human
|
||||
// определяем метод в Human
|
||||
func (h *Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
fmt.Printf("Привет, меня зовут %s, моете позвонить мне по телефону %s\n", h.name, h.phone)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
mark := Student{Human{"Марк", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Сэм", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
|
||||
mark.SayHi()
|
||||
sam.SayHi()
|
||||
}
|
||||
|
||||
### Method overload
|
||||
### Перегрузка методов
|
||||
|
||||
If we want Employee to have its own method `SayHi`, we can define a method that has the same name in Employee, and it will hide `SayHi` in Human when we call it.
|
||||
Если мы хотим, чтобы у Employee был свой метод `SayHi`, мы можем определить метод с таким именем в Employee, и когда мы будем его вызывать, он скроет метод с тем же именем в Human.
|
||||
|
||||
package main
|
||||
import "fmt"
|
||||
@@ -285,26 +282,26 @@ If we want Employee to have its own method `SayHi`, we can define a method that
|
||||
}
|
||||
|
||||
func (h *Human) SayHi() {
|
||||
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||
fmt.Printf("Привет, меня зовут %s, можете позвонить мне по телефону %s\n", h.name, h.phone)
|
||||
}
|
||||
|
||||
func (e *Employee) SayHi() {
|
||||
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
||||
e.company, e.phone) //Yes you can split into 2 lines here.
|
||||
fmt.Printf("Привет, меня зовут %s, я работаю в %s. Звоните мне по телефону %s\n", e.name,
|
||||
e.company, e.phone) //Да, здесь можно разбить строку на две.
|
||||
}
|
||||
|
||||
func main() {
|
||||
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
mark := Student{Human{"Марк", 25, "222-222-YYYY"}, "MIT"}
|
||||
sam := Employee{Human{"Сэм", 45, "111-888-XXXX"}, "Golang Inc"}
|
||||
|
||||
mark.SayHi()
|
||||
sam.SayHi()
|
||||
}
|
||||
|
||||
You are able to write an Object-oriented program now, and methods use rule of capital letter to decide whether public or private as well.
|
||||
Сейчас Вы уже можете написать объектно-ориентированную программу. Методы, начинающиеся с заглавной буквы, являются публичными, с маленькой - приватными.
|
||||
|
||||
## Links
|
||||
## Ссылки
|
||||
|
||||
- [Directory](preface.md)
|
||||
- Previous section: [struct](02.4.md)
|
||||
- Next section: [interface](02.6.md)
|
||||
- [Содержание](preface.md)
|
||||
- Предыдущий раздел: [Структуры](02.4.md)
|
||||
- Следующий раздел: [Интерфейсы](02.6.md)
|
||||
|
||||
Reference in New Issue
Block a user