Add en/0.2.6.md syntax highlighting
This commit is contained in:
518
en/02.6.md
518
en/02.6.md
@@ -19,70 +19,72 @@ This combination of methods is called an interface and is implemented by both St
|
|||||||
### Type of Interface
|
### Type of Interface
|
||||||
|
|
||||||
An interface defines a set of methods, so if a type implements all the methods we say that it implements the interface.
|
An interface defines a set of methods, so if a type implements all the methods we say that it implements the 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("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Human) Sing(lyrics string) {
|
func (h *Human) Sing(lyrics string) {
|
||||||
fmt.Println("La la, la la la, la la la la la...", lyrics)
|
fmt.Println("La la, la la la, la la la la la...", 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 overloads Sayhi
|
// Employee overloads Sayhi
|
||||||
func (e *Employee) SayHi() {
|
func (e *Employee) SayHi() {
|
||||||
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
||||||
e.company, e.phone) //Yes you can split into 2 lines here.
|
e.company, e.phone) //Yes you can split into 2 lines here.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Student) BorrowMoney(amount float32) {
|
func (s *Student) BorrowMoney(amount float32) {
|
||||||
s.loan += amount // (again and again and...)
|
s.loan += amount // (again and again and...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Employee) SpendSalary(amount float32) {
|
func (e *Employee) SpendSalary(amount float32) {
|
||||||
e.money -= amount // More vodka please!!! Get me through the day!
|
e.money -= amount // More vodka please!!! Get me through the day!
|
||||||
}
|
}
|
||||||
|
|
||||||
// define interface
|
// define interface
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
```
|
||||||
We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously.
|
We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously.
|
||||||
|
|
||||||
Note that any type implements the empty interface `interface{}` because it doesn't have any methods and all types have zero methods by default.
|
Note that any type implements the empty interface `interface{}` because it doesn't have any methods and all types have zero methods by default.
|
||||||
@@ -92,87 +94,87 @@ Note that any type implements the empty interface `interface{}` because it doesn
|
|||||||
So what kind of values can be put in the interface? If we define a variable as a type interface, any type that implements the interface can assigned to this variable.
|
So what kind of values can be put in the interface? If we define a variable as a type interface, any type that implements the interface can assigned to this variable.
|
||||||
|
|
||||||
Like the above example, if we define a variable "m" as interface Men, then any one of Student, Human or Employee can be assigned to "m". So we could have a slice of Men, and any type that implements interface Men can assign to this slice. Be aware however that the slice of interface doesn't have the same behavior as a slice of other types.
|
Like the above example, if we define a variable "m" as interface Men, then any one of Student, Human or Employee can be assigned to "m". So we could have a slice of Men, and any type that implements interface Men can assign to this slice. Be aware however that the slice of interface doesn't have the same behavior as a slice of other types.
|
||||||
|
```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("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Human) Sing(lyrics string) {
|
|
||||||
fmt.Println("La la la la...", lyrics)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Employee) SayHi() {
|
|
||||||
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
|
||||||
e.company, e.phone) //Yes you can split into 2 lines here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface Men implemented by Human, Student and Employee
|
|
||||||
type Men interface {
|
|
||||||
SayHi()
|
|
||||||
Sing(lyrics string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
|
|
||||||
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
|
|
||||||
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
|
||||||
tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
|
||||||
|
|
||||||
// define interface i
|
|
||||||
var i Men
|
|
||||||
|
|
||||||
//i can store Student
|
|
||||||
i = mike
|
|
||||||
fmt.Println("This is Mike, a Student:")
|
|
||||||
i.SayHi()
|
|
||||||
i.Sing("November rain")
|
|
||||||
|
|
||||||
//i can store Employee
|
|
||||||
i = tom
|
|
||||||
fmt.Println("This is Tom, an Employee:")
|
|
||||||
i.SayHi()
|
|
||||||
i.Sing("Born to be wild")
|
|
||||||
|
|
||||||
// slice of Men
|
|
||||||
fmt.Println("Let's use a slice of Men and see what happens")
|
|
||||||
x := make([]Men, 3)
|
|
||||||
// these three elements are different types but they all implemented interface 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("Hi, I am %s you can call me on %s\n", h.name, h.phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Human) Sing(lyrics string) {
|
||||||
|
fmt.Println("La la la la...", lyrics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Employee) SayHi() {
|
||||||
|
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
|
||||||
|
e.company, e.phone) //Yes you can split into 2 lines here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface Men implemented by Human, Student and Employee
|
||||||
|
type Men interface {
|
||||||
|
SayHi()
|
||||||
|
Sing(lyrics string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
|
||||||
|
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
|
||||||
|
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
|
||||||
|
tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
|
||||||
|
|
||||||
|
// define interface i
|
||||||
|
var i Men
|
||||||
|
|
||||||
|
//i can store Student
|
||||||
|
i = mike
|
||||||
|
fmt.Println("This is Mike, a Student:")
|
||||||
|
i.SayHi()
|
||||||
|
i.Sing("November rain")
|
||||||
|
|
||||||
|
//i can store Employee
|
||||||
|
i = tom
|
||||||
|
fmt.Println("This is Tom, an Employee:")
|
||||||
|
i.SayHi()
|
||||||
|
i.Sing("Born to be wild")
|
||||||
|
|
||||||
|
// slice of Men
|
||||||
|
fmt.Println("Let's use a slice of Men and see what happens")
|
||||||
|
x := make([]Men, 3)
|
||||||
|
// these three elements are different types but they all implemented interface Men
|
||||||
|
x[0], x[1], x[2] = paul, sam, mike
|
||||||
|
|
||||||
|
for _, value := range x {
|
||||||
|
value.SayHi()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
An interface is a set of abstract methods, and can be implemented by non-interface types. It cannot therefore implement itself.
|
An interface is a set of abstract methods, and can be implemented by non-interface types. It cannot therefore implement itself.
|
||||||
|
|
||||||
### Empty interface
|
### Empty interface
|
||||||
|
|
||||||
An empty interface is an interface that doesn't contain any methods, so all types implement an empty interface. This fact is very useful when we want to store all types at some point, and is similar to void* in C.
|
An empty interface is an interface that doesn't contain any methods, so all types implement an empty interface. This fact is very useful when we want to store all types at some point, and is similar to void* in C.
|
||||||
|
```Go
|
||||||
// define a as empty interface
|
// define a as empty interface
|
||||||
var a interface{}
|
var a interface{}
|
||||||
var i int = 5
|
var i int = 5
|
||||||
@@ -180,7 +182,7 @@ An empty interface is an interface that doesn't contain any methods, so all type
|
|||||||
// a can store value of any type
|
// a can store value of any type
|
||||||
a = i
|
a = i
|
||||||
a = s
|
a = s
|
||||||
|
```
|
||||||
If a function uses an empty interface as its argument type, it can accept any type; if a function uses empty interface as its return value type, it can return any type.
|
If a function uses an empty interface as its argument type, it can accept any type; if a function uses empty interface as its return value type, it can return any type.
|
||||||
|
|
||||||
### Method arguments of an interface
|
### Method arguments of an interface
|
||||||
@@ -188,42 +190,42 @@ If a function uses an empty interface as its argument type, it can accept any ty
|
|||||||
Any variable can be used in an interface. So how can we use this feature to pass any type of variable to a function?
|
Any variable can be used in an interface. So how can we use this feature to pass any type of variable to a function?
|
||||||
|
|
||||||
For example we use fmt.Println a lot, but have you ever noticed that it can accept any type of argument? Looking at the open source code of fmt, we see the following definition.
|
For example we use fmt.Println a lot, but have you ever noticed that it can accept any type of argument? Looking at the open source code of fmt, we see the following definition.
|
||||||
|
```Go
|
||||||
type Stringer interface {
|
type Stringer interface {
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
```
|
||||||
This means any type that implements interface Stringer can be passed to fmt.Println as an argument. Let's prove it.
|
This means any type that implements interface Stringer can be passed to fmt.Println as an argument. Let's prove it.
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
package main
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
import (
|
type Human struct {
|
||||||
"fmt"
|
name string
|
||||||
"strconv"
|
age int
|
||||||
)
|
phone string
|
||||||
|
}
|
||||||
|
|
||||||
type Human struct {
|
// Human implemented fmt.Stringer
|
||||||
name string
|
func (h Human) String() string {
|
||||||
age int
|
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
|
||||||
phone string
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Human implemented fmt.Stringer
|
func main() {
|
||||||
func (h Human) String() string {
|
Bob := Human{"Bob", 39, "000-7777-XXX"}
|
||||||
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
|
fmt.Println("This Human is : ", Bob)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
```
|
||||||
Bob := Human{"Bob", 39, "000-7777-XXX"}
|
|
||||||
fmt.Println("This Human is : ", Bob)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Looking back to the example of Box, you will find that Color implements interface Stringer as well, so we are able to customize the print format. If we don't implement this interface, fmt.Println prints the type with its default format.
|
Looking back to the example of Box, you will find that Color implements interface Stringer as well, so we are able to customize the print format. If we don't implement this interface, fmt.Println prints the type with its default format.
|
||||||
|
```Go
|
||||||
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
|
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
|
||||||
fmt.Println("The biggest one is", boxes.BiggestsColor())
|
fmt.Println("The biggest one is", boxes.BiggestsColor())
|
||||||
|
```
|
||||||
Attention: If the type implemented the interface `error`, fmt will call `error()`, so you don't have to implement Stringer at this point.
|
Attention: If the type implemented the interface `error`, fmt will call `error()`, so you don't have to implement Stringer at this point.
|
||||||
|
|
||||||
### Type of variable in an interface
|
### Type of variable in an interface
|
||||||
@@ -237,90 +239,92 @@ Go has the syntax `value, ok := element.(T)`. This checks to see if the variable
|
|||||||
If the element is the type that we expect, ok will be true, false otherwise.
|
If the element is the type that we expect, ok will be true, false otherwise.
|
||||||
|
|
||||||
Let's use an example to see more clearly.
|
Let's use an example to see more clearly.
|
||||||
|
```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 "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||||
func (p Person) String() string {
|
}
|
||||||
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
|
||||||
}
|
func main() {
|
||||||
|
list := make(List, 3)
|
||||||
func main() {
|
list[0] = 1 // an int
|
||||||
list := make(List, 3)
|
list[1] = "Hello" // a string
|
||||||
list[0] = 1 // an int
|
list[2] = Person{"Dennis", 70}
|
||||||
list[1] = "Hello" // a string
|
|
||||||
list[2] = Person{"Dennis", 70}
|
for index, element := range list {
|
||||||
|
if value, ok := element.(int); ok {
|
||||||
for index, element := range list {
|
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||||
if value, ok := element.(int); ok {
|
} else if value, ok := element.(string); ok {
|
||||||
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||||
} else if value, ok := element.(string); ok {
|
} else if value, ok := element.(Person); ok {
|
||||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||||
} else if value, ok := element.(Person); ok {
|
} else {
|
||||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
fmt.Printf("list[%d] is of a different type\n", index)
|
||||||
} else {
|
|
||||||
fmt.Printf("list[%d] is of a different type\n", index)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
It's quite easy to use this pattern, but if we have many types to test, we'd better use `switch`.
|
It's quite easy to use this pattern, but if we have many types to test, we'd better use `switch`.
|
||||||
|
|
||||||
- switch test
|
- switch test
|
||||||
|
|
||||||
Let's use `switch` to rewrite the above example.
|
Let's use `switch` to rewrite the above example.
|
||||||
|
```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 "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
list := make(List, 3)
|
list := make(List, 3)
|
||||||
list[0] = 1 //an int
|
list[0] = 1 //an int
|
||||||
list[1] = "Hello" //a string
|
list[1] = "Hello" //a string
|
||||||
list[2] = Person{"Dennis", 70}
|
list[2] = Person{"Dennis", 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] is an int and its value is %d\n", index, value)
|
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
|
||||||
case string:
|
case string:
|
||||||
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
|
||||||
case Person:
|
case Person:
|
||||||
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
|
||||||
default:
|
default:
|
||||||
fmt.Println("list[%d] is of a different type", index)
|
fmt.Println("list[%d] is of a different type", index)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
One thing you should remember is that `element.(type)` cannot be used outside of the `switch` body, which means in that case you have to use the `comma-ok` pattern .
|
One thing you should remember is that `element.(type)` cannot be used outside of the `switch` body, which means in that case you have to use the `comma-ok` pattern .
|
||||||
|
|
||||||
@@ -329,63 +333,63 @@ One thing you should remember is that `element.(type)` cannot be used outside of
|
|||||||
The most beautiful thing is that Go has a lot of built-in logic syntax, such as anonymous fields in struct. Not suprisingly, we can use interfaces as anonymous fields as well, but we call them `Embedded interfaces`. Here, we follow the same rules as anonymous fields. More specifically, if an interface has another interface embedded within it, it will behave as if it has all the methods that the embedded interface has.
|
The most beautiful thing is that Go has a lot of built-in logic syntax, such as anonymous fields in struct. Not suprisingly, we can use interfaces as anonymous fields as well, but we call them `Embedded interfaces`. Here, we follow the same rules as anonymous fields. More specifically, if an interface has another interface embedded within it, it will behave as if it has all the methods that the embedded interface has.
|
||||||
|
|
||||||
We can see that the source file in `container/heap` has the following definition:
|
We can see that the source file in `container/heap` has the following definition:
|
||||||
|
```Go
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
sort.Interface // embedded sort.Interface
|
sort.Interface // embedded sort.Interface
|
||||||
Push(x interface{}) //a Push method to push elements into the heap
|
Push(x interface{}) //a Push method to push elements into the heap
|
||||||
Pop() interface{} //a Pop method that pops elements from the heap
|
Pop() interface{} //a Pop method that pops elements from the heap
|
||||||
}
|
}
|
||||||
|
```
|
||||||
We see that `sort.Interface` is an embedded interface, so the above Interface has the three methods contained within the `sort.Interface` implicitly.
|
We see that `sort.Interface` is an embedded interface, so the above Interface has the three methods contained within the `sort.Interface` implicitly.
|
||||||
|
```Go
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
// Len is the number of elements in the collection.
|
// Len is the number of elements in the collection.
|
||||||
Len() int
|
Len() int
|
||||||
// Less returns whether the element with index i should sort
|
// Less returns whether the element with index i should sort
|
||||||
// before the element with index j.
|
// before the element with index j.
|
||||||
Less(i, j int) bool
|
Less(i, j int) bool
|
||||||
// Swap swaps the elements with indexes i and j.
|
// Swap swaps the elements with indexes i and j.
|
||||||
Swap(i, j int)
|
Swap(i, j int)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
Another example is the `io.ReadWriter` in package `io`.
|
Another example is the `io.ReadWriter` in package `io`.
|
||||||
|
```Go
|
||||||
// io.ReadWriter
|
// io.ReadWriter
|
||||||
type ReadWriter interface {
|
type ReadWriter interface {
|
||||||
Reader
|
Reader
|
||||||
Writer
|
Writer
|
||||||
}
|
}
|
||||||
|
```
|
||||||
### Reflection
|
### Reflection
|
||||||
|
|
||||||
Reflection in Go is used for determining information at runtime. We use the `reflect` package, and this official [article](http://golang.org/doc/articles/laws_of_reflection.html) explains how reflect works in Go.
|
Reflection in Go is used for determining information at runtime. We use the `reflect` package, and this official [article](http://golang.org/doc/articles/laws_of_reflection.html) explains how reflect works in Go.
|
||||||
|
|
||||||
There are three steps involved when using reflect. First, we need to convert an interface to reflect types (reflect.Type or reflect.Value, this depends on the situation).
|
There are three steps involved when using reflect. First, we need to convert an interface to reflect types (reflect.Type or reflect.Value, this depends on the situation).
|
||||||
|
```Go
|
||||||
t := reflect.TypeOf(i) // get meta-data in type i, and use t to get all elements
|
t := reflect.TypeOf(i) // get meta-data in type i, and use t to get all elements
|
||||||
v := reflect.ValueOf(i) // get actual value in type i, and use v to change its value
|
v := reflect.ValueOf(i) // get actual value in type i, and use v to change its value
|
||||||
|
```
|
||||||
After that, we can convert the reflected types to get the values that we need.
|
After that, we can convert the reflected types to get the values that we need.
|
||||||
|
```Go
|
||||||
var x float64 = 3.4
|
var x float64 = 3.4
|
||||||
v := reflect.ValueOf(x)
|
v := reflect.ValueOf(x)
|
||||||
fmt.Println("type:", v.Type())
|
fmt.Println("type:", v.Type())
|
||||||
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
|
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
|
||||||
fmt.Println("value:", v.Float())
|
fmt.Println("value:", v.Float())
|
||||||
|
```
|
||||||
Finally, if we want to change the values of the reflected types, we need to make it modifiable. As discussed earlier, there is a difference between pass by value and pass by reference. The following code will not compile.
|
Finally, if we want to change the values of the reflected types, we need to make it modifiable. As discussed earlier, there is a difference between pass by value and pass by reference. The following code will not compile.
|
||||||
|
```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)
|
||||||
|
```
|
||||||
Instead, we must use the following code to change the values from reflect types.
|
Instead, we must use the following code to change the values from reflect types.
|
||||||
|
```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)
|
||||||
|
```
|
||||||
We have just discussed the basics of reflection, however you must practice more in order to understand more.
|
We have just discussed the basics of reflection, however you must practice more in order to understand more.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|||||||
Reference in New Issue
Block a user