EDITORIAL
Go Before learning the language, I have a certain foundation of Java and C ++, this article is mainly based on A tour of Go written mainly want to record your own learning process, deepen their understanding
Started Go Language (two) methods and interfaces
method
Go language is no "class" of this concept, but we can define a variable methods, such as the definition of the method structure, to achieve the situation is similar to class. Here We Go first to the method definition:
What is the method
"Method": a class with a special receiver parameter function
For the method, "receiver parameters" is located in func
keywords and 方法名
between:
// 定义一个结构体
type Vertex struct {
X, Y float64
}
// 这里有一个接受者参数 v
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
// 我们可以直接调用 v 的 Abs() 方法
fmt.Println(v.Abs())
}
Of course, we can also be the recipient v as an argument directly, then that is a normal function, and they can achieve the same functionality:
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Receiver parameters
In the above, we define a "receiver parameters" for the structure Vertex
of the Abs()
method, we can be any type of variable declaration method .
Here we use type
the keyword to define a variable type "MyFloat":
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
}
Note: only the type of recipient declaration methods defined in the same package, but not the other as defined packet types (including built-in types such as int) method recipient declaration.
Pointer recipients
For an understanding of other languages, we know that is actually a copy of the operating parameters of the function; and because there is "pointer", there are "arguments" and "parameter" of the points.
In Go also has a presence both, for certain types of T:
If the type parameter is the recipient
T
, it is a "parameter", modify the function does not modify the original elements;If the type parameter is the recipient
*T
, it is the "argument", it points to the elements can be modified directly in the function, so the ability to synchronize modify the original elements.
See the examples below:
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
// 对于方法,Go 可以自动在值和指针之间转换
v.Scale(10)
fmt.Println(v.Abs())
}
When we define the method of time, Go language will help us automatically between values and pointers ; similar to the above, if the method needs a value, but we passed is a pointer, Go can help us to automatically convert. But it is not automatically converted when using the function .
Therefore, we can directly use v.Scale(10)
the execution result here is 50; if we Scale()
receiver to process parameters v Vertext
, the Scale
function is passed the parameter, the copy just modify elements run the same value v, performed the result is 5.
Generally, all methods of a given type should have a pointer value or the recipient, but both should not be mixed . (We'll see why below.)
interface
Unlike in Java interfaces, in Go, the interface is an abstract type . It's like a kind of "agreement", all of the interface type can reference all the methods it provides.
"Interface Type": a set of methods defined by the signature collection
type Abser interface {
Abs() float64
}
How to Use Interface
If a type implements an interface required by all methods , then this type will implement this interface.
We look at the following code example:
package main
import (
"fmt"
"math"
)
// 接口 Abser,包含方法 Abs()
type Abser interface {
Abs() float64
}
// MyFloat 实现了 Abs() 方法
type MyFloat float64
// 无需使用 implements 关键字
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
// *Vertex 实现了 Abs() 方法
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
f := MyFloat(-math.Sqrt2)
v := Vertex{3, 4}
a = f // a MyFloat 实现了 Abser
a = &v // a *Vertex 实现了 Abser
// 这里被注释的语句会报错
// v 是一个 Vertex(而不是 *Vertex),没有实现 Abser。
// a := v
fmt.Println(a.Abs())
fmt.Println(b.Abs())
}
The example code, type MyFloat
and type *Vertex
implement a Abs()
method, it is possible to interface type Abser
assignment; and Vertex
not implemented, if it will be assigned an error.
At the same time, we can also see from the above code, the realization Abser
when the interface method, we did not achieve the same interfaces as Java, with implements
explicit declaration of keywords, which would also encourage programmers to have a clear definition of the interface.
Interface value
"Connectors" as an abstract type, it is also a value, like other values can be passed as is, it can be used as parameters or return values.
Here we define an interface I
, type *T
and M
implements this interface, and then we will be the interface I
as a parameter function desribe()
in:
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
// 实现 I 的类型 *T
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
// 实现 I 的类型 F
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
// 打印传入接口的值和类型
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
After the operation, the output is as follows:
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
Can be seen, the incoming interface parameters are printed at the bottom of the types and values.
The underlying value is nil interface
If the interface of a specific value is nil
, then call this method interface, in some languages (such as Java) will trigger a "null pointer exception", but in Go can be printed out correctly nil.
Note: Save the nil
specific value of the interface itself is not nil
.
We use the precedent of the interface I
and type *T
, make the test as follows:
1. "Interface specific value" is nil
func main() {
var i I
var t *T
i = t
describe(i)
i.M()
}
Execution results are as follows:
(<nil>, *main.T)
<nil>
It can be seen in the i call the method M()
when, Go can normally print out the <nil>
value and does not complain.
2. "connectors" itself is nil
func main() {
var i I
describe(i)
i.M()
}
Implementation of the above statement, describe()
the method can print out (<nil>, <nil>)
, it indicates that the interface itself as a nil
natural value is also nil
; but when i of the interface method calls will throw an exception (because Go do not know what should be called the specific type of the method).
Air Interface
"Air Interface": defines the interface method 0
interface{}
Air interface has what effect? It is possible to accept any type of value (because the method does not require air interface), so we can use the interface null process value of an unknown type . For example, fmt.Print
an acceptable type of interface{}
an arbitrary number of parameters.
The following example can effectively help us to understand:
func main() {
var i interface{}
describe(i)
// 运行结果: (<nil>, <nil>)
i = 42k
describe(i)
// 运行结果: (42, int)
i = "hello"
describe(i)
// 运行结果: (hello, string)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
The above describe()
function will be to empty interface as a parameter, it is possible to accept the value of any type (including nil) of.
Type assertion
"Type assertion": provides access to the underlying value of the specific value of the interface mode.
t := i.(T)
The statement asserts the interface type specific stored value T i, and t is the underlying type to the variable value of T.
If i did not hold the value of type T, the statement will trigger a panic panic
.
For determining a value of the interface to save a particular type, the type assertion returns two values: the value of the underlying report and a Boolean value assertion success.
t, ok := i.(T)
This "double assignment" and the map is very similar:
If i holds a T, it
t
will be the underlying value, andok
is true.Otherwise, the
ok
willfalse
and t will be zero value of type T, the program does not panic .
Let's use an example to sum up the interface "type assertion ':
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
// 执行结果: hello
s, ok := i.(string)
fmt.Println(s, ok)
// 执行结果: hello true
f, ok := i.(float64)
fmt.Println(f, ok)
// 执行结果: 0 false
f = i.(float64)
fmt.Println(f)
// 报错(panic)
}
Type selection
"Type selection": one kind of structure in order to select from several branches of the type of assertion.
Go apply in swtich
the statement, the interface can be for a given value of the stored types of values are compared:
switch v := i.(type) {
case T:
// v 的类型为 T
case S:
// v 的类型为 S
default:
// 没有匹配,v 与 i 的类型相同
}
Type Select the type of assertion in a statement i.(T)
the same syntax, but the specific type T
is replaced by a keyword type
.
This type of statement to determine the value of the interface to select the value of i is stored in T or S.
In the case of S or T, respectively will be variable v T or S type has the value of i stored.
In the default (i.e. no match), the variables i and v values and the same type of interface.
Note: "Type Select" only the interface type is suitable , we can not be used for other types of values.
Common Interface: Stringer
fmt
Defined in the package Stringer
is one of the most common interface, which is similar to the Java toString()
method, we can achieve it defines how the output from the caller.
fmt
Package defined as follows:
type Stringer interface {
String() string
}
Below we achieved through Stringer
the interface, the output from the structure defined Person
values:
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("Person: %v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a)
fmt.Println(z)
}
Output:
Person: Arthur Dent (42 years)
Person: Zaphod Beeblebrox (9001 years)
Common Interface: error
Go with error
values indicate an error condition. And fmt.Stringer
similar error
type is a built-in interfaces:
type error interface {
Error() string
}
And fmt.Stringer
similar fmt
package when printing error value will satisfy us to achieve (or default) error
, so we can realize Error()
the error message to be printed from the definition of the method.
So, whether an error how to get it? Go with the still familiar "double assignment."
Typically function returns a error
value, it may be determined whether the code calls the error is equal nil
to error processing.
error
Is nil, indicates a successful execution, no errorerror
Is not nil, represent fails, an error occurred
i, err := strconv.Atoi("42")
if err != nil {
fmt.Printf("couldn't convert number: %v\n", err)
return
}
fmt.Println("Converted integer:", i)
Let's use an example to try error
interface, we realize a function prescribing, and let its argument is negative when an error occurs:
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
// 注意:这里要 float64(e),不然会产生死循环
return fmt.Sprint(float64(e))
}
func Sqrt(x float64) (float64, error) {
if x < 0 {
return 0, ErrNegativeSqrt(x)
}
return math.Sqrt(x), nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
Results are as follows:
1.4142135623730951 <nil>
0 -2
It should explain why Error()
not direct printing method in e
which you want to print float64(e)
:
Because the fmt
packet will attempt to match the output error
, achieved by the variable E Error()
becomes a function of the interface error
type, fmt.Sprint(e)
when invoked e.Error()
to output an error message string, which is equivalent to the following code:
func (e MyError) Error() string {
return fmt.Printf(e)
}
// e 是一个 error,上面的语句实际上是这样的
// 这也就产生来死循环
func (e MyError) Error() string {
return fmt.Printf(e.Error())
}
Common Interface: Reader
io
Packages specify io.Reader
the interface that represents the reading from the end of the data stream .
Go standard library contains the interface many implementations , including files, network connections, compression and encryption, and so on.
io.Reader
Interface has one Read()
method:
func (T) Read(b []byte) (n int, err error)
Read()
Way to do two things:
Data filling the given byte slice;
Return -filled "bytes" and "error value."
In the face of the end of the data stream, it will return an io.EOF
error.
Sample code creates a strings.Reader
and 8 bytes at a time to read speed of its output:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Hello, Reader!")
b := make([]byte, 8)
for {
n, err := r.Read(b)
fmt.Printf("n = %v err = %v b = %v\n", n, err, b)
fmt.Printf("b[:n] = %q\n", b[:n])
if err == io.EOF {
break
}
}
}
Execution results are as follows:
// 第一次循环
n = 8 err = <nil> b = [72 101 108 108 111 44 32 82]
b[:n] = "Hello, R"
// 第二次循环
n = 6 err = <nil> b = [101 97 100 101 114 33 32 82]
b[:n] = "eader!"
// 第三次循环,遇到 EOF 异常,表示读取完毕,结束循环
n = 0 err = EOF b = [101 97 100 101 114 33 32 82]
b[:n] = ""
We can "of Go A tour" through online exercises to practice on the use of Reader interface.
Below we achieve a Reader
type that produces an ASCII character 'A' infinite stream.
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
// TODO: 给 MyReader 添加一个 Read([]byte) (int, error) 方法
func (r MyReader) Read(b []byte) (int, error) {
// 1.填充字节切片
b[0] = 'A'
// 2.返回填充的字符数和错误值
return 1, nil
}
func main() {
reader.Validate(MyReader{})
}
Common Interface: Image
image
Package defines Image
interfaces:
package image
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x , y int) color.Color
}
Note: Bounds()
The return value method "Rectangle" is actually a image.Rectangle
, it is image
a statement package.
color.Color
And the color.Model
type is an interface, but usually because the direct use predefined achieve image.RGBA
and image.RGBAModel
be ignored. These types of interfaces and image/color
custom package. Here you can learn more about image
the packet.