format code snippets like Go code & typos fixes

This commit is contained in:
Andrey Krasavin
2019-03-22 08:51:16 +03:00
committed by GitHub
parent d970f1d772
commit c30beb9dc7

View File

@@ -19,70 +19,70 @@
### Тип "Interface"
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
```Go
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type Student struct {
Human
school string
loan float32
}
type Employee struct {
Human
company string
money 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) SayHi() {
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
}
func (h *Human) Sing(lyrics string) {
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
}
func (h *Human) Sing(lyrics string) {
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
}
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// Employee перегружает метод SayHi
func (e *Employee) SayHi() {
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
e.company, e.phone) //Да, можно разбить строку на 2 строки.
}
// Employee перегружает метод SayHi
func (e *Employee) SayHi() {
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
e.company, e.phone) //Да, можно разбить строку на 2 строки.
}
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (снова и снова...)
}
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (снова и снова...)
}
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount
}
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount
}
// определяем интерфейс
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
// определяем интерфейс
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
```
Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно.
Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов.
@@ -92,95 +92,95 @@
Итак, какие типы значений может принимать интерфейс? Если мы определили переменную типа interface, то значение любого типа, который реализует этот интерфейс, может быть присвоено этой переменной.
Как в примере выше, если мы определили переменную "m" как интерфейс Men, то все значения типа Student, Human или Employee могут быть присвоены переменной "m". Так что у нас может быть срез элементов типа Men, и значение любого типа, реализующего интерфейс Men, может присвоено элементам этого среза. Но имейте в виду, что срез элементов типа interface не ведет себя так же, как срез из элементов других типов.
```Go
package main
package main
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()
}
}
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()
}
}
```
Интерфейс - это набор абстрактных методов, он может быть реализован типами, не являющимися интерфейсами. Поэтому он не может быть реализован самим собой.
### Пустой интерфейс
Пустой интерфейс - это интерфейс, который не содержит методов. Это очен полезно, если мы хотим хранить данные любого типа в одном месте, и это похоже на void* в C.
// Определим a как пустой интерфейс
var a interface{}
var i int = 5
s := "Привет, мир!"
// a может принимать значение любого типа
a = i
a = s
Пустой интерфейс - это интерфейс, который не содержит методов. Это очень полезно, если мы хотим хранить данные любого типа в одном месте, и это похоже на void* в C.
```Go
// Определим a как пустой интерфейс
var a interface{}
var i int = 5
s := "Привет, мир!"
// a может принимать значение любого типа
a = i
a = s
```
Если функция использует пустой интерфейс в качестве входного аргумента, она может принимать значения любого типа; если функция использует пустой интерфейс в качестве возвращаемого значения, она может возвращать значения любого типа.
### Интерфейсы как аргументы методов
@@ -196,37 +196,37 @@ type Stringer interface {
```
Это значит, что любой тип, реализующий интерфейс Stringer, может быть передан в качестве аргумента в fmt.Println. Давайте докажем это:
```Go
package main
package main
import (
"fmt"
"strconv"
)
import (
"fmt"
"strconv"
)
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
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)
}
// 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)
}
```
Возвращаясь к примеру с Box можно обнаружить, что Color также реализует интерфейс Stringer, поэтому у нас есть возможность изменить формат вывода информации. Если не реализовать этот интерфейс, fmt.Println выведет тип на печать в формате по умолчанию.
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor().String())
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor())
Внимание: Если тип реализует интерфейс `error`, fmt вызовет `error()`, поэтому в этом случае Вам не надо реализовывать Stringer.
```Go
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor().String())
fmt.Println("Самая большая коробка: ", boxes.BiggestsColor())
```
Внимание: Если тип реализует интерфейс `error`, fmt вызовет `Error()`, поэтому в этом случае Вам не надо реализовывать Stringer.
### Тип переменной в интерфейсе
@@ -239,90 +239,90 @@ type Stringer interface {
Если element является переменной типа, который мы указали, ok будет равен true, иначе - false.
Чтобы было понятнее, посмотрим на пример:
```Go
package main
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
func main() {
list := make(List, 3)
list[0] = 1 // целочисленный тип
list[1] = "Привет" // строка
list[2] = Person{"Деннис", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] - это целое число, его значение - %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] - это строка, его значение - %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] - это Person, его значение %s\n", index, value)
} else {
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index)
}
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
func main() {
list := make(List, 3)
list[0] = 1 // целочисленный тип
list[1] = "Привет" // строка
list[2] = Person{"Деннис", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] - это целое число, его значение - %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] - это строка, его значение - %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] - это Person, его значение %s\n", index, value)
} else {
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index)
}
}
}
```
Пользоваться этим шаблоном довольно-таки просто, но если надо протестировать много типов, лучше воспользоваться `switch`.
- тест с использованием switch
Давайте перепишем наш пример с использованием `switch`.
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
func main() {
list := make(List, 3)
list[0] = 1 // целое число
list[1] = "Hello" // строка
list[2] = Person{"Деннис", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] - целое число, его значение - %d\n", index, value)
case string:
fmt.Printf("list[%d] - строка, его значение - %s\n", index, value)
case Person:
fmt.Printf("list[%d] - Person, его значение - %s\n", index, value)
default:
fmt.Println("list[%d] - данные какого-то другого типа", index)
}
```Go
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
func main() {
list := make(List, 3)
list[0] = 1 // целое число
list[1] = "Hello" // строка
list[2] = Person{"Деннис", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] - целое число, его значение - %d\n", index, value)
case string:
fmt.Printf("list[%d] - строка, его значение - %s\n", index, value)
case Person:
fmt.Printf("list[%d] - Person, его значение - %s\n", index, value)
default:
fmt.Println("list[%d] - данные какого-то другого типа", index)
}
}
}
```
Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`.
@@ -331,63 +331,63 @@ type Stringer interface {
В синтаксисе Go существует множество встроенной логики, такой, например, как анонимные поля в структуре. Неудивительно, что мы можем использовать в качестве анонимных полей и интерфейсы тоже, но называются они `Встроенные интерфейсы`. В этом случае мы следуем тем же правилам, что и в случае со встроенными полями. А точнее, если в интерфейс встроен другой интерфейс, то этот интерфейс будет иметь в себе все методы встроенного интерфейса.
В исходном коде пакета `container/heap` мы можем видеть следующее определение:
type Interface interface {
sort.Interface // встраиваемый sort.Interface
Push(x interface{}) // метод Push для того, чтобы помещать элементы в кучу
Pop() interface{} // метод Pop, который изымает элементы из кучи
}
```Go
type Interface interface {
sort.Interface // встраиваемый sort.Interface
Push(x interface{}) // метод Push для того, чтобы помещать элементы в кучу
Pop() interface{} // метод Pop, который изымает элементы из кучи
}
```
Мы видим, что `sort.Interface` является встраиваемым интерфейсом, поэтому в Interface неявно присутствуют три метода, содержащиеся внутри `sort.Interface`:
type Interface interface {
// Len - количество элементов в коллекции
Len() int
// Less определяет, надо ли перемещать элемент с индексом i
// перед элементом с индексом j.
Less(i, j int) bool
// Swap меняем местами элементы с индексами i и j.
Swap(i, j int)
}
```Go
type Interface interface {
// Len - количество элементов в коллекции
Len() int
// Less определяет, надо ли перемещать элемент с индексом i
// перед элементом с индексом j.
Less(i, j int) bool
// Swap меняем местами элементы с индексами i и j.
Swap(i, j int)
}
```
Другой пример - `io.ReadWriter` из пакета `io`.
// io.ReadWriter
type ReadWriter interface {
Reader
Writer
}
```Go
// io.ReadWriter
type ReadWriter interface {
Reader
Writer
}
```
### Рефлексия
Рефлексия в Go используется для определения информации во время выполнения программы. Мы пользумеся пакетом `reflect`, и эта официальная [статья](http://golang.org/doc/articles/laws_of_reflection.html) объясняет, как reflect работает в Go.
В процессе использования reflect задействованы 3 шага. Во-первых, нужно конвертировать интерфейс в типы reflect (reflect.Type или reflect.Value в зависимости от ситуации).
t := reflect.TypeOf(i) // получает мета-данные типа i в переменную t
v := reflect.ValueOf(i) // получает значение типа i в переменную v
```Go
t := reflect.TypeOf(i) // получает мета-данные типа i в переменную t
v := reflect.ValueOf(i) // получает значение типа i в переменную v
```
После этого мы может конвертировать типы, полученные в результате рефлексии, для того, чтобы получить нужные нам значения.
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("Тип:", v.Type())
fmt.Println("Вид является float64:", v.Kind() == reflect.Float64)
fmt.Println("Значение:", v.Float())
```Go
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("Тип:", v.Type())
fmt.Println("Вид является float64:", v.Kind() == reflect.Float64)
fmt.Println("Значение:", v.Float())
```
Наконец, если мы хотим изменить значения типов, полученных в результате рефлексии, нам нужно сделать их изменяемыми. Как было обсуждено ранее, есть разница между передачей по ссылке и по значению. Следующий код не скомпилируется:
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
```Go
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
```
Вместо этого для изменения значений типов, полученных в результате рефлексии, нам нужно использовать следующий код:
var x float64 = 3.4
p := reflect.ValueOf(&x)
v := p.Elem()
v.SetFloat(7.1)
```Go
var x float64 = 3.4
p := reflect.ValueOf(&x)
v := p.Elem()
v.SetFloat(7.1)
```
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
## Ссылки