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

format code snippets like Go code & typos fixes

上级 d970f1d7
......@@ -19,70 +19,70 @@
### Тип "Interface"
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
type Human struct {
```Go
type Human struct {
name string
age int
phone string
}
}
type Student struct {
type Student struct {
Human
school string
loan float32
}
}
type Employee struct {
type Employee struct {
Human
company string
money float32
}
}
func (h *Human) SayHi() {
func (h *Human) SayHi() {
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
}
}
func (h *Human) Sing(lyrics string) {
func (h *Human) Sing(lyrics string) {
fmt.Println("Ля ля, ля ля ля, ля ля ля ля ля...", lyrics)
}
}
func (h *Human) Guzzle(beerStein string) {
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
}
// Employee перегружает метод SayHi
func (e *Employee) SayHi() {
// 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) {
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (снова и снова...)
}
}
func (e *Employee) SpendSalary(amount float32) {
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount
}
}
// определяем интерфейс
type Men interface {
// определяем интерфейс
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
}
type YoungChap interface {
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
}
type ElderlyGent interface {
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
}
```
Интерфейс может быть реализован любым типом данных, и один тип может реализовывать несколько интерфейсов одновременно.
Заметьте, что все типы реализуют пустой интерфейс `interface{}`, так как у него нет методов, а все типы изначально также не имеют методов.
......@@ -92,49 +92,49 @@
Итак, какие типы значений может принимать интерфейс? Если мы определили переменную типа 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
age int
phone string
}
}
type Student struct {
type Student struct {
Human
school string
loan float32
}
}
type Employee struct {
type Employee struct {
Human
company string
money float32
}
}
func (h Human) SayHi() {
func (h Human) SayHi() {
fmt.Printf("Привет, я - %s, мой номер телефона - %s\n", h.name, h.phone)
}
}
func (h Human) Sing(lyrics string) {
func (h Human) Sing(lyrics string) {
fmt.Println("Ля ля ля ля...", lyrics)
}
}
func (e Employee) SayHi() {
func (e Employee) SayHi() {
fmt.Printf("Привет, я - %s, я работаю в %s. Звоните мне по номеру %s\n", e.name,
e.company, e.phone) //Да, здесь можно разбить строку на две.
}
}
// Интерфейс Men реализуется типами Human, Student и Employee
type Men interface {
// Интерфейс Men реализуется типами Human, Student и Employee
type Men interface {
SayHi()
Sing(lyrics string)
}
}
func main() {
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}
......@@ -164,23 +164,23 @@
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 (
import (
"fmt"
"strconv"
)
)
type Human struct {
type Human struct {
name string
age int
phone string
}
}
// Human реализует fmt.Stringer
func (h Human) String() string {
// Human реализует fmt.Stringer
func (h Human) String() string {
return "Имя:" + h.name + ", Возраст:" + strconv.Itoa(h.age) + " years, Контакт:" + h.phone
}
}
func main() {
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,27 +239,27 @@ type Stringer interface {
Если element является переменной типа, который мы указали, ok будет равен true, иначе - false.
Чтобы было понятнее, посмотрим на пример:
```Go
package main
package main
import (
import (
"fmt"
"strconv"
)
)
type Element interface{}
type List []Element
type Element interface{}
type List []Element
type Person struct {
type Person struct {
name string
age int
}
}
func (p Person) String() string {
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
}
func main() {
func main() {
list := make(List, 3)
list[0] = 1 // целочисленный тип
list[1] = "Привет" // строка
......@@ -276,34 +276,34 @@ type Stringer interface {
fmt.Printf("list[%d] - это данные какого-то другого типа\n", index)
}
}
}
}
```
Пользоваться этим шаблоном довольно-таки просто, но если надо протестировать много типов, лучше воспользоваться `switch`.
- тест с использованием switch
Давайте перепишем наш пример с использованием `switch`.
```Go
package main
package main
import (
import (
"fmt"
"strconv"
)
)
type Element interface{}
type List []Element
type Element interface{}
type List []Element
type Person struct {
type Person struct {
name string
age int
}
}
func (p Person) String() string {
func (p Person) String() string {
return "(Имя: " + p.name + " - возраст: " + strconv.Itoa(p.age) + " лет)"
}
}
func main() {
func main() {
list := make(List, 3)
list[0] = 1 // целое число
list[1] = "Hello" // строка
......@@ -321,8 +321,8 @@ type Stringer interface {
fmt.Println("list[%d] - данные какого-то другого типа", index)
}
}
}
}
```
Нужно запомнить, что конструкция `element.(type)` не может быть использована вне тела `switch`, в этом случае надо использовать шаблон `запятая-ok`.
......@@ -331,16 +331,16 @@ type Stringer interface {
В синтаксисе Go существует множество встроенной логики, такой, например, как анонимные поля в структуре. Неудивительно, что мы можем использовать в качестве анонимных полей и интерфейсы тоже, но называются они `Встроенные интерфейсы`. В этом случае мы следуем тем же правилам, что и в случае со встроенными полями. А точнее, если в интерфейс встроен другой интерфейс, то этот интерфейс будет иметь в себе все методы встроенного интерфейса.
В исходном коде пакета `container/heap` мы можем видеть следующее определение:
type Interface interface {
```Go
type Interface interface {
sort.Interface // встраиваемый sort.Interface
Push(x interface{}) // метод Push для того, чтобы помещать элементы в кучу
Pop() interface{} // метод Pop, который изымает элементы из кучи
}
}
```
Мы видим, что `sort.Interface` является встраиваемым интерфейсом, поэтому в Interface неявно присутствуют три метода, содержащиеся внутри `sort.Interface`:
type Interface interface {
```Go
type Interface interface {
// Len - количество элементов в коллекции
Len() int
// Less определяет, надо ли перемещать элемент с индексом i
......@@ -348,46 +348,46 @@ type Stringer interface {
Less(i, j int) bool
// Swap меняем местами элементы с индексами i и j.
Swap(i, j int)
}
}
```
Другой пример - `io.ReadWriter` из пакета `io`.
// io.ReadWriter
type ReadWriter interface {
```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)
```
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
## Ссылки
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册