Error
Go
使用error
类型的值来表示错误,这是一个内建的类似Stringer
的接口。
1 2 3
| type error interface { Error() string }
|
类似Stringer
,fmt
包也会寻找error
接口来打印值。
函数经常以error
作为返回类型,调用函数的代码应该通过检测error
是否为nil
并处理处理。一般来说error == nil
说明无错误,而非nil则代表failure.
error练习
实现一个开方函数,除返回结果外,还返回error
,当被操作数是负数是返回一个非nil
的error
,其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.EOF
的error
.
下例中使用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) }
|
运行:
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.Color
和color.Model
都是接口,但是我们将暂时略过它们而使用预实现的color.RGBA
和color.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()) }
|
运行:
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) }
|
打印的图片是