Merge pull request #1075 from drypa/patch-2
format code snippets like Go code & typos fixes
This commit is contained in:
562
ru/02.6.md
562
ru/02.6.md
@@ -19,70 +19,70 @@
|
|||||||
### Тип "Interface"
|
### Тип "Interface"
|
||||||
|
|
||||||
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
|
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
|
||||||
|
```Go
|
||||||
|
type Human struct {
|
||||||
|
name string
|
||||||
|
age int
|
||||||
|
phone string
|
||||||
|
}
|
||||||
|
|
||||||
type Human struct {
|
type Student struct {
|
||||||
name string
|
Human
|
||||||
age int
|
school string
|
||||||
phone string
|
loan float32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Student struct {
|
type Employee struct {
|
||||||
Human
|
Human
|
||||||
school string
|
company string
|
||||||
loan float32
|
money float32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Employee struct {
|
func (h *Human) SayHi() {
|
||||||
Human
|
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
|
||||||
company string
|
}
|
||||||
money float32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Human) SayHi() {
|
func (h *Human) Sing(lyrics string) {
|
||||||
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
|
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Human) Sing(lyrics string) {
|
func (h *Human) Guzzle(beerStein string) {
|
||||||
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
|
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Human) Guzzle(beerStein string) {
|
// Employee перегружает метод SayHi
|
||||||
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
|
func (e *Employee) SayHi() {
|
||||||
}
|
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
|
||||||
|
e.company, e.phone) //Да, можно разбить строку на 2 строки.
|
||||||
|
}
|
||||||
|
|
||||||
// Employee перегружает метод SayHi
|
func (s *Student) BorrowMoney(amount float32) {
|
||||||
func (e *Employee) SayHi() {
|
s.loan += amount // (снова и снова...)
|
||||||
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
|
}
|
||||||
e.company, e.phone) //Да, можно разбить строку на 2 строки.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Student) BorrowMoney(amount float32) {
|
func (e *Employee) SpendSalary(amount float32) {
|
||||||
s.loan += amount // (снова и снова...)
|
e.money -= amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Employee) SpendSalary(amount float32) {
|
// определяем интерфейс
|
||||||
e.money -= amount
|
type Men interface {
|
||||||
}
|
SayHi()
|
||||||
|
Sing(lyrics string)
|
||||||
|
Guzzle(beerStein string)
|
||||||
|
}
|
||||||
|
|
||||||
// определяем интерфейс
|
type YoungChap interface {
|
||||||
type Men interface {
|
SayHi()
|
||||||
SayHi()
|
Sing(song string)
|
||||||
Sing(lyrics string)
|
BorrowMoney(amount float32)
|
||||||
Guzzle(beerStein string)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type YoungChap interface {
|
|
||||||
SayHi()
|
|
||||||
Sing(song string)
|
|
||||||
BorrowMoney(amount float32)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ElderlyGent interface {
|
|
||||||
SayHi()
|
|
||||||
Sing(song string)
|
|
||||||
SpendSalary(amount float32)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
type ElderlyGent interface {
|
||||||
|
SayHi()
|
||||||
|
Sing(song string)
|
||||||
|
SpendSalary(amount float32)
|
||||||
|
}
|
||||||
|
```
|
||||||
Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно.
|
Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно.
|
||||||
|
|
||||||
Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов.
|
Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов.
|
||||||
@@ -92,95 +92,95 @@
|
|||||||
Итак, какие типы значений может принимать интерфейс? Если мы определили переменную типа interface, то значение любого типа, который реализует этот интерфейс, может быть присвоено этой переменной.
|
Итак, какие типы значений может принимать интерфейс? Если мы определили переменную типа interface, то значение любого типа, который реализует этот интерфейс, может быть присвоено этой переменной.
|
||||||
|
|
||||||
Как в примере выше, если мы определили переменную "m" как интерфейс Men, то все значения типа Student, Human или Employee могут быть присвоены переменной "m". Так что у нас может быть срез элементов типа Men, и значение любого типа, реализующего интерфейс Men, может присвоено элементам этого среза. Но имейте в виду, что срез элементов типа interface не ведет себя так же, как срез из элементов других типов.
|
Как в примере выше, если мы определили переменную "m" как интерфейс Men, то все значения типа Student, Human или Employee могут быть присвоены переменной "m". Так что у нас может быть срез элементов типа Men, и значение любого типа, реализующего интерфейс Men, может присвоено элементам этого среза. Но имейте в виду, что срез элементов типа interface не ведет себя так же, как срез из элементов других типов.
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
package main
|
import "fmt"
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type Human struct {
|
|
||||||
name string
|
|
||||||
age int
|
|
||||||
phone string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Student struct {
|
|
||||||
Human
|
|
||||||
school string
|
|
||||||
loan float32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Employee struct {
|
|
||||||
Human
|
|
||||||
company string
|
|
||||||
money float32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Human) SayHi() {
|
|
||||||
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Human) Sing(lyrics string) {
|
|
||||||
fmt.Println("Ля ля ля ля...", lyrics)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Employee) SayHi() {
|
|
||||||
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
|
|
||||||
e.company, e.phone) //Да, здесь можно разбить строку на две.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Интерфейс Men реализуется типами Human, Student и Employee
|
|
||||||
type Men interface {
|
|
||||||
SayHi()
|
|
||||||
Sing(lyrics string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
mike := Student{Human{"Майк", 25, "222-222-XXX"}, "MIT", 0.00}
|
|
||||||
paul := Student{Human{"Пол", 26, "111-222-XXX"}, "Harvard", 100}
|
|
||||||
sam := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
|
||||||
tom := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
|
||||||
|
|
||||||
// определяем интерфейс i
|
|
||||||
var i Men
|
|
||||||
|
|
||||||
//i может быть Student
|
|
||||||
i = mike
|
|
||||||
fmt.Println("Это Майк, студент:")
|
|
||||||
i.SayHi()
|
|
||||||
i.Sing("November rain")
|
|
||||||
|
|
||||||
//i может быть Employee
|
|
||||||
i = tom
|
|
||||||
fmt.Println("Это Том, работник:")
|
|
||||||
i.SayHi()
|
|
||||||
i.Sing("Born to be wild")
|
|
||||||
|
|
||||||
// срез из элементов типа Men
|
|
||||||
fmt.Println("Давайте создадим срез из Men и посмотрим, что получится")
|
|
||||||
x := make([]Men, 3)
|
|
||||||
// Эти три элемента относятся к разным типам, но все они реализуют интерфейс Men
|
|
||||||
x[0], x[1], x[2] = paul, sam, mike
|
|
||||||
|
|
||||||
for _, value := range x {
|
|
||||||
value.SayHi()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
type Human struct {
|
||||||
|
name string
|
||||||
|
age int
|
||||||
|
phone string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Student struct {
|
||||||
|
Human
|
||||||
|
school string
|
||||||
|
loan float32
|
||||||
|
}
|
||||||
|
|
||||||
|
type Employee struct {
|
||||||
|
Human
|
||||||
|
company string
|
||||||
|
money float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Human) SayHi() {
|
||||||
|
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Human) Sing(lyrics string) {
|
||||||
|
fmt.Println("Ля ля ля ля...", lyrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Employee) SayHi() {
|
||||||
|
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
|
||||||
|
e.company, e.phone) //Да, здесь можно разбить строку на две.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Интерфейс Men реализуется типами Human, Student и Employee
|
||||||
|
type Men interface {
|
||||||
|
SayHi()
|
||||||
|
Sing(lyrics string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mike := Student{Human{"Майк", 25, "222-222-XXX"}, "MIT", 0.00}
|
||||||
|
paul := Student{Human{"Пол", 26, "111-222-XXX"}, "Harvard", 100}
|
||||||
|
sam := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||||
|
tom := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||||
|
|
||||||
|
// определяем интерфейс i
|
||||||
|
var i Men
|
||||||
|
|
||||||
|
//i может быть Student
|
||||||
|
i = mike
|
||||||
|
fmt.Println("Это Майк, студент:")
|
||||||
|
i.SayHi()
|
||||||
|
i.Sing("November rain")
|
||||||
|
|
||||||
|
//i может быть Employee
|
||||||
|
i = tom
|
||||||
|
fmt.Println("Это Том, работник:")
|
||||||
|
i.SayHi()
|
||||||
|
i.Sing("Born to be wild")
|
||||||
|
|
||||||
|
// срез из элементов типа Men
|
||||||
|
fmt.Println("Давайте создадим срез из Men и посмотрим, что получится")
|
||||||
|
x := make([]Men, 3)
|
||||||
|
// Эти три элемента относятся к разным типам, но все они реализуют интерфейс Men
|
||||||
|
x[0], x[1], x[2] = paul, sam, mike
|
||||||
|
|
||||||
|
for _, value := range x {
|
||||||
|
value.SayHi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Интерфейс - это набор абстрактных методов, он может быть реализован типами, не являющимися интерфейсами. Поэтому он не может быть реализован самим собой.
|
Интерфейс - это набор абстрактных методов, он может быть реализован типами, не являющимися интерфейсами. Поэтому он не может быть реализован самим собой.
|
||||||
|
|
||||||
### Пустой интерфейс
|
### Пустой интерфейс
|
||||||
|
|
||||||
Пустой интерфейс - это интерфейс, который не содержит методов. Это очен полезно, если мы хотим хранить данные любого типа в одном месте, и это похоже на void* в C.
|
Пустой интерфейс - это интерфейс, который не содержит методов. Это очень полезно, если мы хотим хранить данные любого типа в одном месте, и это похоже на void* в C.
|
||||||
|
```Go
|
||||||
// Определим a как пустой интерфейс
|
// Определим a как пустой интерфейс
|
||||||
var a interface{}
|
var a interface{}
|
||||||
var i int = 5
|
var i int = 5
|
||||||
s := "Привет, мир!"
|
s := "Привет, мир!"
|
||||||
// a может принимать значение любого типа
|
// a может принимать значение любого типа
|
||||||
a = i
|
a = i
|
||||||
a = s
|
a = s
|
||||||
|
```
|
||||||
Если функция использует пустой интерфейс в качестве входного аргумента, она может принимать значения любого типа; если функция использует пустой интерфейс в качестве возвращаемого значения, она может возвращать значения любого типа.
|
Если функция использует пустой интерфейс в качестве входного аргумента, она может принимать значения любого типа; если функция использует пустой интерфейс в качестве возвращаемого значения, она может возвращать значения любого типа.
|
||||||
|
|
||||||
### Интерфейсы как аргументы методов
|
### Интерфейсы как аргументы методов
|
||||||
@@ -196,37 +196,37 @@ type Stringer interface {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Это значит, что любой тип, реализующий интерфейс Stringer, может быть передан в качестве аргумента в fmt.Println. Давайте докажем это:
|
Это значит, что любой тип, реализующий интерфейс Stringer, может быть передан в качестве аргумента в fmt.Println. Давайте докажем это:
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
package main
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
import (
|
type Human struct {
|
||||||
"fmt"
|
name string
|
||||||
"strconv"
|
age int
|
||||||
)
|
phone string
|
||||||
|
}
|
||||||
|
|
||||||
type Human struct {
|
// Human реализует fmt.Stringer
|
||||||
name string
|
func (h Human) String() string {
|
||||||
age int
|
return "Имя:" + h.name + ", Возраст:" + strconv.Itoa(h.age) + " years, Контакт:" + h.phone
|
||||||
phone string
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Human реализует fmt.Stringer
|
|
||||||
func (h Human) String() string {
|
|
||||||
return "Имя:" + h.name + ", Возраст:" + strconv.Itoa(h.age) + " years, Контакт:" + h.phone
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
Bob := Human{"Боб", 39, "000-7777-XXX"}
|
|
||||||
fmt.Println("Этот человек: ", Bob)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
Bob := Human{"Боб", 39, "000-7777-XXX"}
|
||||||
|
fmt.Println("Этот человек: ", Bob)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Возвращаясь к примеру с Box можно обнаружить, что Color также реализует интерфейс Stringer, поэтому у нас есть возможность изменить формат вывода информации. Если не реализовать этот интерфейс, fmt.Println выведет тип на печать в формате по умолчанию.
|
Возвращаясь к примеру с Box можно обнаружить, что Color также реализует интерфейс Stringer, поэтому у нас есть возможность изменить формат вывода информации. Если не реализовать этот интерфейс, fmt.Println выведет тип на печать в формате по умолчанию.
|
||||||
|
```Go
|
||||||
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor().String())
|
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor().String())
|
||||||
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor())
|
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor())
|
||||||
|
```
|
||||||
Внимание: Если тип реализует интерфейс `error`, fmt вызовет `error()`, поэтому в этом случае Вам не надо реализовывать Stringer.
|
Внимание: Если тип реализует интерфейс `error`, fmt вызовет `Error()`, поэтому в этом случае Вам не надо реализовывать Stringer.
|
||||||
|
|
||||||
### Тип переменной в интерфейсе
|
### Тип переменной в интерфейсе
|
||||||
|
|
||||||
@@ -239,90 +239,90 @@ type Stringer interface {
|
|||||||
Если element является переменной типа, который мы указали, ok будет равен true, иначе - false.
|
Если element является переменной типа, который мы указали, ok будет равен true, иначе - false.
|
||||||
|
|
||||||
Чтобы было понятнее, посмотрим на пример:
|
Чтобы было понятнее, посмотрим на пример:
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
package main
|
import (
|
||||||
|
"fmt"
|
||||||
import (
|
"strconv"
|
||||||
"fmt"
|
)
|
||||||
"strconv"
|
|
||||||
)
|
type Element interface{}
|
||||||
|
type List []Element
|
||||||
type Element interface{}
|
|
||||||
type List []Element
|
type Person struct {
|
||||||
|
name string
|
||||||
type Person struct {
|
age int
|
||||||
name string
|
}
|
||||||
age int
|
|
||||||
}
|
func (p Person) String() string {
|
||||||
|
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
|
||||||
func (p Person) String() string {
|
}
|
||||||
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
|
|
||||||
}
|
func main() {
|
||||||
|
list := make(List, 3)
|
||||||
func main() {
|
list[0] = 1 // целочисленный тип
|
||||||
list := make(List, 3)
|
list[1] = "Привет" // строка
|
||||||
list[0] = 1 // целочисленный тип
|
list[2] = Person{"Деннис", 70}
|
||||||
list[1] = "Привет" // строка
|
|
||||||
list[2] = Person{"Деннис", 70}
|
for index, element := range list {
|
||||||
|
if value, ok := element.(int); ok {
|
||||||
for index, element := range list {
|
fmt.Printf("list[%d] - это целое число, его значение - %d\n", index, value)
|
||||||
if value, ok := element.(int); ok {
|
} else if value, ok := element.(string); ok {
|
||||||
fmt.Printf("list[%d] - это целое число, его значение - %d\n", index, value)
|
fmt.Printf("list[%d] - это строка, его значение - %s\n", index, value)
|
||||||
} else if value, ok := element.(string); ok {
|
} else if value, ok := element.(Person); ok {
|
||||||
fmt.Printf("list[%d] - это строка, его значение - %s\n", index, value)
|
fmt.Printf("list[%d] - это Person, его значение %s\n", index, value)
|
||||||
} else if value, ok := element.(Person); ok {
|
} else {
|
||||||
fmt.Printf("list[%d] - это Person, его значение %s\n", index, value)
|
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index)
|
||||||
} else {
|
|
||||||
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
Пользоваться этим шаблоном довольно-таки просто, но если надо протестировать много типов, лучше воспользоваться `switch`.
|
Пользоваться этим шаблоном довольно-таки просто, но если надо протестировать много типов, лучше воспользоваться `switch`.
|
||||||
|
|
||||||
- тест с использованием switch
|
- тест с использованием switch
|
||||||
|
|
||||||
Давайте перепишем наш пример с использованием `switch`.
|
Давайте перепишем наш пример с использованием `switch`.
|
||||||
|
```Go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Element interface{}
|
type Element interface{}
|
||||||
type List []Element
|
type List []Element
|
||||||
|
|
||||||
type Person struct {
|
type Person struct {
|
||||||
name string
|
name string
|
||||||
age int
|
age int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Person) String() string {
|
func (p Person) String() string {
|
||||||
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
|
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
list := make(List, 3)
|
list := make(List, 3)
|
||||||
list[0] = 1 // целое число
|
list[0] = 1 // целое число
|
||||||
list[1] = "Hello" // строка
|
list[1] = "Hello" // строка
|
||||||
list[2] = Person{"Деннис", 70}
|
list[2] = Person{"Деннис", 70}
|
||||||
|
|
||||||
for index, element := range list {
|
for index, element := range list {
|
||||||
switch value := element.(type) {
|
switch value := element.(type) {
|
||||||
case int:
|
case int:
|
||||||
fmt.Printf("list[%d] - целое число, его значение - %d\n", index, value)
|
fmt.Printf("list[%d] - целое число, его значение - %d\n", index, value)
|
||||||
case string:
|
case string:
|
||||||
fmt.Printf("list[%d] - строка, его значение - %s\n", index, value)
|
fmt.Printf("list[%d] - строка, его значение - %s\n", index, value)
|
||||||
case Person:
|
case Person:
|
||||||
fmt.Printf("list[%d] - Person, его значение - %s\n", index, value)
|
fmt.Printf("list[%d] - Person, его значение - %s\n", index, value)
|
||||||
default:
|
default:
|
||||||
fmt.Println("list[%d] - данные какого-то другого типа", index)
|
fmt.Println("list[%d] - данные какого-то другого типа", index)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`.
|
Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`.
|
||||||
|
|
||||||
@@ -331,63 +331,63 @@ type Stringer interface {
|
|||||||
В синтаксисе Go существует множество встроенной логики, такой, например, как анонимные поля в структуре. Неудивительно, что мы можем использовать в качестве анонимных полей и интерфейсы тоже, но называются они `Встроенные интерфейсы`. В этом случае мы следуем тем же правилам, что и в случае со встроенными полями. А точнее, если в интерфейс встроен другой интерфейс, то этот интерфейс будет иметь в себе все методы встроенного интерфейса.
|
В синтаксисе Go существует множество встроенной логики, такой, например, как анонимные поля в структуре. Неудивительно, что мы можем использовать в качестве анонимных полей и интерфейсы тоже, но называются они `Встроенные интерфейсы`. В этом случае мы следуем тем же правилам, что и в случае со встроенными полями. А точнее, если в интерфейс встроен другой интерфейс, то этот интерфейс будет иметь в себе все методы встроенного интерфейса.
|
||||||
|
|
||||||
В исходном коде пакета `container/heap` мы можем видеть следующее определение:
|
В исходном коде пакета `container/heap` мы можем видеть следующее определение:
|
||||||
|
```Go
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
sort.Interface // встраиваемый sort.Interface
|
sort.Interface // встраиваемый sort.Interface
|
||||||
Push(x interface{}) // метод Push для того, чтобы помещать элементы в кучу
|
Push(x interface{}) // метод Push для того, чтобы помещать элементы в кучу
|
||||||
Pop() interface{} // метод Pop, который изымает элементы из кучи
|
Pop() interface{} // метод Pop, который изымает элементы из кучи
|
||||||
}
|
}
|
||||||
|
```
|
||||||
Мы видим, что `sort.Interface` является встраиваемым интерфейсом, поэтому в Interface неявно присутствуют три метода, содержащиеся внутри `sort.Interface`:
|
Мы видим, что `sort.Interface` является встраиваемым интерфейсом, поэтому в Interface неявно присутствуют три метода, содержащиеся внутри `sort.Interface`:
|
||||||
|
```Go
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
// Len - количество элементов в коллекции
|
// Len - количество элементов в коллекции
|
||||||
Len() int
|
Len() int
|
||||||
// Less определяет, надо ли перемещать элемент с индексом i
|
// Less определяет, надо ли перемещать элемент с индексом i
|
||||||
// перед элементом с индексом j.
|
// перед элементом с индексом j.
|
||||||
Less(i, j int) bool
|
Less(i, j int) bool
|
||||||
// Swap меняем местами элементы с индексами i и j.
|
// Swap меняем местами элементы с индексами i и j.
|
||||||
Swap(i, j int)
|
Swap(i, j int)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
Другой пример - `io.ReadWriter` из пакета `io`.
|
Другой пример - `io.ReadWriter` из пакета `io`.
|
||||||
|
```Go
|
||||||
// io.ReadWriter
|
// io.ReadWriter
|
||||||
type ReadWriter interface {
|
type ReadWriter interface {
|
||||||
Reader
|
Reader
|
||||||
Writer
|
Writer
|
||||||
}
|
}
|
||||||
|
```
|
||||||
### Рефлексия
|
### Рефлексия
|
||||||
|
|
||||||
Рефлексия в Go используется для определения информации во время выполнения программы. Мы пользумеся пакетом `reflect`, и эта официальная [статья](http://golang.org/doc/articles/laws_of_reflection.html) объясняет, как reflect работает в Go.
|
Рефлексия в Go используется для определения информации во время выполнения программы. Мы пользумеся пакетом `reflect`, и эта официальная [статья](http://golang.org/doc/articles/laws_of_reflection.html) объясняет, как reflect работает в Go.
|
||||||
|
|
||||||
В процессе использования reflect задействованы 3 шага. Во-первых, нужно конвертировать интерфейс в типы reflect (reflect.Type или reflect.Value в зависимости от ситуации).
|
В процессе использования reflect задействованы 3 шага. Во-первых, нужно конвертировать интерфейс в типы reflect (reflect.Type или reflect.Value в зависимости от ситуации).
|
||||||
|
```Go
|
||||||
t := reflect.TypeOf(i) // получает мета-данные типа i в переменную t
|
t := reflect.TypeOf(i) // получает мета-данные типа i в переменную t
|
||||||
v := reflect.ValueOf(i) // получает значение типа i в переменную v
|
v := reflect.ValueOf(i) // получает значение типа i в переменную v
|
||||||
|
```
|
||||||
После этого мы может конвертировать типы, полученные в результате рефлексии, для того, чтобы получить нужные нам значения.
|
После этого мы может конвертировать типы, полученные в результате рефлексии, для того, чтобы получить нужные нам значения.
|
||||||
|
```Go
|
||||||
var x float64 = 3.4
|
var x float64 = 3.4
|
||||||
v := reflect.ValueOf(x)
|
v := reflect.ValueOf(x)
|
||||||
fmt.Println("Тип:", v.Type())
|
fmt.Println("Тип:", v.Type())
|
||||||
fmt.Println("Вид является float64:", v.Kind() == reflect.Float64)
|
fmt.Println("Вид является float64:", v.Kind() == reflect.Float64)
|
||||||
fmt.Println("Значение:", v.Float())
|
fmt.Println("Значение:", v.Float())
|
||||||
|
```
|
||||||
Наконец, если мы хотим изменить значения типов, полученных в результате рефлексии, нам нужно сделать их изменяемыми. Как было обсуждено ранее, есть разница между передачей по ссылке и по значению. Следующий код не скомпилируется:
|
Наконец, если мы хотим изменить значения типов, полученных в результате рефлексии, нам нужно сделать их изменяемыми. Как было обсуждено ранее, есть разница между передачей по ссылке и по значению. Следующий код не скомпилируется:
|
||||||
|
```Go
|
||||||
var x float64 = 3.4
|
var x float64 = 3.4
|
||||||
v := reflect.ValueOf(x)
|
v := reflect.ValueOf(x)
|
||||||
v.SetFloat(7.1)
|
v.SetFloat(7.1)
|
||||||
|
```
|
||||||
Вместо этого для изменения значений типов, полученных в результате рефлексии, нам нужно использовать следующий код:
|
Вместо этого для изменения значений типов, полученных в результате рефлексии, нам нужно использовать следующий код:
|
||||||
|
```Go
|
||||||
var x float64 = 3.4
|
var x float64 = 3.4
|
||||||
p := reflect.ValueOf(&x)
|
p := reflect.ValueOf(&x)
|
||||||
v := p.Elem()
|
v := p.Elem()
|
||||||
v.SetFloat(7.1)
|
v.SetFloat(7.1)
|
||||||
|
```
|
||||||
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
|
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
|
||||||
|
|
||||||
## Ссылки
|
## Ссылки
|
||||||
|
|||||||
Reference in New Issue
Block a user