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"
|
||||
|
||||
Интерфейс определяет набор методов, поэтому, если тип реализует эти методы, говорится, что он реализует интерфейс.
|
||||
```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)
|
||||
```
|
||||
Мы здесь обсудили основы рефлексии, однако, чтобы больше понять, Вы должны больше практиковаться.
|
||||
|
||||
## Ссылки
|
||||
|
||||
Reference in New Issue
Block a user