Contents
  1. 1. Error
    1. 1.1. error练习
  2. 2. Readers
    1. 2.1. Reader练习
    2. 2.2. 练习:rot13Reader
  3. 3. Image接口
    1. 3.1. image练习

Error

Go使用error类型的值来表示错误,这是一个内建的类似Stringer的接口。

1
2
3
type error interface {
Error() string
}

类似Stringer,fmt包也会寻找error接口来打印值。

函数经常以error作为返回类型,调用函数的代码应该通过检测error是否为nil并处理处理。一般来说error == nil说明无错误,而非nil则代表failure.

error练习

实现一个开方函数,除返回结果外,还返回error,当被操作数是负数是返回一个非nilerror,其Error()方法返回“cannot Sqrt negative number: -2”信息。
创建一个MyFloat的类type MyFloat float64,然后实现func (mf MyFloat ) Error() string使之成为一个error
这是我的答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main
import ( "fmt"
"math")
type MyFloat float64
func (mf MyFloat) Error() string{
return fmt.Sprintf("cannot Sqrt negative number:%v.\n",float64(mf))
}
func Sqrt(f float64) (float64,error){
if f < 0 {
return 0, MyFloat(f)
}
return math.Sqrt(f),nil
}
func main(){
fmt.Println(Sqrt(4.3))
fmt.Println(Sqrt(-5.2))
}

运行:

1
2
2.073644135332772 <nil>
0 cannot Sqrt negative number:-5.2.

这里需要注意的一点是,在Error()方法里,当用Sprintf返回string时,一定要将其强制转换为基本类型float64,否则就会进入死循环直到stack overflow.这是因为Error方法的Sprintf语句中打印MyFloat类型又会调用Error,从而进入死循环。

Readers

io包中定义了io.Reader接口,代表数据stream的读取端。Go的标准库包含这些接口的多种实现,包括文件、网络、压缩器、加密器等。
io.reader接口有一个Read方法:

1
func (T) Read(b []byte) (n int, err error)

Read向指定的slice中填充数据并返回读取的字节数和一个error,当文件结束时它返回一个io.EOFerror.
下例中使用NewReader方法创建了一个io.Reader并使用其Read方法一次读入8字节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
}
}
}

Reader练习

实现一个Reader类型,从中能读出无穷的'A'字符。
这个应该是比较简单地,直接给出我的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
// TODO: Add a Read([]byte) (int, error) method to MyReader.
func (mr MyReader) Read(b []byte) (int ,error){
len := 0
for i := range b{
b[i] = 'A'
len ++
}
return len ,nil
}
func main() {
reader.Validate(MyReader{})
}

练习:rot13Reader

一种常见的模式是用一个io.Reader包装另一个io.Reader,以对stream实现修改。
例如gzip.NewReader函数接收一个io.Reader(压缩数据的stream),返回一个*gzip.Reader,它也是一个io.Reader(一个已解压数据的stream).

题目:实现一个rot13Reader,它从一个io.Reader中读取数据并实现rot13加密算法(所有字母顺移13位。
这个题目有一点工作量,以下是我的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func isAlphabet(c byte) bool {
return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
func rot13(c byte) byte {
if c >= 'a' && c <= 'z' {
if c += 13; c > 'z' {
c = c%'z' + 'a' - 1
}
}
if c >= 'A' && c <= 'Z' {
if c += 13; c > 'Z' {
c = c%'Z' + 'A' - 1
}
}
return c
}
func (r rot13Reader) Read(b []byte) (int, error) {
n, e := r.r.Read(b)
for i := 0; i < n; i++ {
if isAlphabet(b[i]) {
b[i] = rot13(b[i])
}
if e == io.EOF {
break
}
}
return n, e
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}

运行:

1
You cracked the code!

Image接口

image包定义了Image接口

1
2
3
4
5
6
7
package image
type Image interface {
ColorModel() color.Model
Bounds() Rectangle
At(x, y int) color.Color
}

其中Bounds方法返回的Rectangle类型实质是image.Rectangle,因为它是在包内定义的。
详细信息https://golang.org/pkg/image/#Image
color.Colorcolor.Model都是接口,但是我们将暂时略过它们而使用预实现的color.RGBAcolor.GRGBAModel。这些接口和类型在image/color package中定义

1
2
3
4
5
6
7
8
9
10
11
12
package main
import (
"fmt"
"image"
)
func main() {
m := image.NewRGBA(image.Rect(0, 0, 100, 100))
fmt.Println(m.Bounds())
fmt.Println(m.At(0, 0).RGBA())
}

运行:

1
2
(0,0)-(100,100)
0 0 0 0

image练习

还记得之前的生成图像练习吗?不过这次我们要实现一个image.Image而不是一个slice.
定义你自己的Image类型,实现必要的方法,并调用pic.ShowImage()

1
2
3
4
5
6
7
8
9
10
11
type Image interface {
// ColorModel returns the Image's color model.
ColorModel() color.Model
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
Bounds() Rectangle
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
At(x, y int) color.Color
}

Bounds应该返回一个image.Rectangle,类似image.Rect(0,0,w,h).
ColorModel应该返回color.RGBAModel

事实以上教程可能比较老了,当我查阅了新的Image相关api文档之后,类似Rect这样的type都已经换了形式。以下是我的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main
import "golang.org/x/tour/pic"
import "image/color"
import "image"
type Image struct {
w, h int
colr uint8
}
func (i Image) ColorModel() color.Model {
return color.RGBAModel
}
func (i Image) Bounds() image.Rectangle {
return image.Rectangle{image.Point{i.w, i.h}, image.Point{110, 110}}
}
func (i Image) At(x, y int) color.Color {
return color.RGBA{i.colr+uint8(x), i.colr+uint8(y), 255, 255}
}
func main() {
m := Image{0,0,50}
pic.ShowImage(m)
}

打印的图片是

Contents
  1. 1. Error
    1. 1.1. error练习
  2. 2. Readers
    1. 2.1. Reader练习
    2. 2.2. 练习:rot13Reader
  3. 3. Image接口
    1. 3.1. image练习