未验证 提交 c30beb9d 编写于 作者: A Andrey Krasavin 提交者: GitHub

format code snippets like Go code & typos fixes

上级 d970f1d7
...@@ -19,70 +19,70 @@ ...@@ -19,70 +19,70 @@
### Тип "Interface" ### Тип "Interface"
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс. Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
```Go
type Human struct { type Human struct {
name string name string
age int age int
phone string phone string
} }
type Student struct { type Student struct {
Human Human
school string school string
loan float32 loan float32
} }
type Employee struct { type Employee struct {
Human Human
company string company string
money float32 money float32
} }
func (h *Human) SayHi() { func (h *Human) SayHi() {
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone) fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
} }
func (h *Human) Sing(lyrics string) { func (h *Human) Sing(lyrics string) {
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics) fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
} }
func (h *Human) Guzzle(beerStein string) { func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein) fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
} }
// Employee перегружает метод SayHi // Employee перегружает метод SayHi
func (e *Employee) SayHi() { func (e *Employee) SayHi() {
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name, fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
e.company, e.phone) //Да, можно разбить строку на 2 строки. e.company, e.phone) //Да, можно разбить строку на 2 строки.
} }
func (s *Student) BorrowMoney(amount float32) { func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (снова и снова...) s.loan += amount // (снова и снова...)
} }
func (e *Employee) SpendSalary(amount float32) { func (e *Employee) SpendSalary(amount float32) {
e.money -= amount e.money -= amount
} }
// определяем интерфейс // определяем интерфейс
type Men interface { type Men interface {
SayHi() SayHi()
Sing(lyrics string) Sing(lyrics string)
Guzzle(beerStein string) Guzzle(beerStein string)
} }
type YoungChap interface { type YoungChap interface {
SayHi() SayHi()
Sing(song string) Sing(song string)
BorrowMoney(amount float32) BorrowMoney(amount float32)
} }
type ElderlyGent interface { type ElderlyGent interface {
SayHi() SayHi()
Sing(song string) Sing(song string)
SpendSalary(amount float32) SpendSalary(amount float32)
} }
```
Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно. Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно.
Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов. Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов.
...@@ -92,49 +92,49 @@ ...@@ -92,49 +92,49 @@
Итак, какие типы значений может принимать интерфейс? Если мы определили переменную типа 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 { type Human struct {
name string name string
age int age int
phone string phone string
} }
type Student struct { type Student struct {
Human Human
school string school string
loan float32 loan float32
} }
type Employee struct { type Employee struct {
Human Human
company string company string
money float32 money float32
} }
func (h Human) SayHi() { func (h Human) SayHi() {
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone) fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
} }
func (h Human) Sing(lyrics string) { func (h Human) Sing(lyrics string) {
fmt.Println("Ля ля ля ля...", lyrics) fmt.Println("Ля ля ля ля...", lyrics)
} }
func (e Employee) SayHi() { func (e Employee) SayHi() {
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name, fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
e.company, e.phone) //Да, здесь можно разбить строку на две. e.company, e.phone) //Да, здесь можно разбить строку на две.
} }
// Интерфейс Men реализуется типами Human, Student и Employee // Интерфейс Men реализуется типами Human, Student и Employee
type Men interface { type Men interface {
SayHi() SayHi()
Sing(lyrics string) Sing(lyrics string)
} }
func main() { func main() {
mike := Student{Human{"Майк", 25, "222-222-XXX"}, "MIT", 0.00} mike := Student{Human{"Майк", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Пол", 26, "111-222-XXX"}, "Harvard", 100} paul := Student{Human{"Пол", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Golang Inc.", 1000} sam := Employee{Human{"Сэм", 36, "444-222-XXX"}, "Golang Inc.", 1000}
...@@ -164,23 +164,23 @@ ...@@ -164,23 +164,23 @@
for _, value := range x { for _, value := range x {
value.SayHi() 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 { ...@@ -196,37 +196,37 @@ type Stringer interface {
``` ```
Это значит, что любой тип, реализующий интерфейс Stringer, может быть передан в качестве аргумента в fmt.Println. Давайте докажем это: Это значит, что любой тип, реализующий интерфейс Stringer, может быть передан в качестве аргумента в fmt.Println. Давайте докажем это:
```Go
package main
package main import (
import (
"fmt" "fmt"
"strconv" "strconv"
) )
type Human struct { type Human struct {
name string name string
age int age int
phone string phone string
} }
// Human реализует fmt.Stringer // Human реализует fmt.Stringer
func (h Human) String() string { func (h Human) String() string {
return "Имя:" + h.name + ", Возраст:" + strconv.Itoa(h.age) + " years, Контакт:" + h.phone return "Имя:" + h.name + ", Возраст:" + strconv.Itoa(h.age) + " years, Контакт:" + h.phone
} }
func main() { func main() {
Bob := Human{"Боб", 39, "000-7777-XXX"} Bob := Human{"Боб", 39, "000-7777-XXX"}
fmt.Println("Этот человек: ", Bob) 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,27 +239,27 @@ type Stringer interface { ...@@ -239,27 +239,27 @@ type Stringer interface {
Если element является переменной типа, который мы указали, ok будет равен true, иначе - false. Если element является переменной типа, который мы указали, ok будет равен true, иначе - false.
Чтобы было понятнее, посмотрим на пример: Чтобы было понятнее, посмотрим на пример:
```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] = "Привет" // строка list[1] = "Привет" // строка
...@@ -276,34 +276,34 @@ type Stringer interface { ...@@ -276,34 +276,34 @@ type Stringer interface {
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index) 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" // строка
...@@ -321,8 +321,8 @@ type Stringer interface { ...@@ -321,8 +321,8 @@ type Stringer interface {
fmt.Println("list[%d] - данные какого-то другого типа", index) fmt.Println("list[%d] - данные какого-то другого типа", index)
} }
} }
} }
```
Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`. Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`.
...@@ -331,16 +331,16 @@ type Stringer interface { ...@@ -331,16 +331,16 @@ 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
...@@ -348,46 +348,46 @@ type Stringer interface { ...@@ -348,46 +348,46 @@ type Stringer interface {
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)
```
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться. Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
## Ссылки ## Ссылки
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册