golang notes(3)

1, Execise: Errors

Note: A call to fmt.Sprint(e) inside the Error method will send the program into an infinite loop. You can avoid this by converting e first: fmt.Sprint(float64(e)). Why?

package main

import (
	"fmt"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("can't Sqrt negative number: %v\n", float64(e))
	//return fmt.Sprintf("can't Sqrt negative number: %v\n", e)
}

func Sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, ErrNegativeSqrt(x)
	}

	z := 1.0
	//z := x/2
	//z := x
	for i := 0; i < 10; i++ {
		diff := z*z - x
		fmt.Printf("z = %v, diff = %v\n", z, diff)
		if math.Abs(diff) < 1.0e-15 {
			return z, nil
		} else {
			z -= diff / (2*z)
		}
	}

	fmt.Printf("Max number of trying reached with next z = %v\n", z)
	return z, nil
}

func main() {
	fmt.Println(Sqrt(2))
	fmt.Println(Sqrt(-2))
}

Output looks like:

z = 1, diff = -1
z = 1.5, diff = 0.25
z = 1.4166666666666667, diff = 0.006944444444444642
z = 1.4142156862745099, diff = 6.007304882871267e-06
z = 1.4142135623746899, diff = 4.510614104447086e-12
z = 1.4142135623730951, diff = 4.440892098500626e-16
1.4142135623730951 <nil>
0 can't Sqrt negative number: -2

But if you are using in ErrNegativeSqrt.Error():

return fmt.Sprintf("can't Sqrt negative number: %v\n", e)

you will get an 'stack overflow':

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200e02f8 stack=[0xc0200e0000, 0xc0400e0000]
fatal error: stack overflow

From the calling stack, we can see that there is an infinite call to ErrNegativeSqrt.Error(): 

main.ErrNegativeSqrt.Error(...)
        /home/dabs/dev/golang/gotour/error/errors.go:30
main.(*ErrNegativeSqrt).Error(0xc006843b40, 0x4b4760, 0xc006843b40)
        <autogenerated>:1 +0x99 fp=0xc020160518 sp=0xc0201604c0 pc=0x49df09
fmt.(*pp).handleMethods(0xc006877520, 0x76, 0xc020160801)
        /usr/local/go/src/fmt/print.go:624 +0x1db fp=0xc020160788 sp=0xc020160518 pc=0x497f6b
fmt.(*pp).printArg(0xc006877520, 0x4b4760, 0xc006843b40, 0x76)
        /usr/local/go/src/fmt/print.go:713 +0x1e4 fp=0xc020160820 sp=0xc020160788 pc=0x498634
fmt.(*pp).doPrintf(0xc006877520, 0x4d2ef7, 0x1f, 0xc020160998, 0x1, 0x1)
        /usr/local/go/src/fmt/print.go:1030 +0x15a fp=0xc020160908 sp=0xc020160820 pc=0x49beda
fmt.Sprintf(0x4d2ef7, 0x1f, 0xc020160998, 0x1, 0x1, 0x4b5d00, 0x42d986)
        /usr/local/go/src/fmt/print.go:219 +0x66 fp=0xc020160960 sp=0xc020160908 pc=0x4950f6
main.ErrNegativeSqrt.Error(...)
        /home/dabs/dev/golang/gotour/error/errors.go:30
main.(*ErrNegativeSqrt).Error(0xc006843b38, 0x4b4760, 0xc006843b38)
        <autogenerated>:1 +0x99 fp=0xc0201609b8 sp=0xc020160960 pc=0x49df09
fmt.(*pp).handleMethods(0xc006877450, 0x76, 0xc020160c01)
        /usr/local/go/src/fmt/print.go:624 +0x1db fp=0xc020160c28 sp=0xc0201609b8 pc=0x497f6b
fmt.(*pp).printArg(0xc006877450, 0x4b4760, 0xc006843b38, 0x76)
        /usr/local/go/src/fmt/print.go:713 +0x1e4 fp=0xc020160cc0 sp=0xc020160c28 pc=0x498634
fmt.(*pp).doPrintf(0xc006877450, 0x4d2ef7, 0x1f, 0xc020160e38, 0x1, 0x1)
        /usr/local/go/src/fmt/print.go:1030 +0x15a fp=0xc020160da8 sp=0xc020160cc0 pc=0x49beda
fmt.Sprintf(0x4d2ef7, 0x1f, 0xc020160e38, 0x1, 0x1, 0x4b5d00, 0x42d986)
        /usr/local/go/src/fmt/print.go:219 +0x66 fp=0xc020160e00 sp=0xc020160da8 pc=0x4950f6
main.ErrNegativeSqrt.Error(...)
        /home/dabs/dev/golang/gotour/error/errors.go:30
main.(*ErrNegativeSqrt).Error(0xc006843b30, 0x4b4760, 0xc006843b30)
        <autogenerated>:1 +0x99 fp=0xc020160e58 sp=0xc020160e00 pc=0x49df09

Below is part of handleMethods of print.go:

One solution is: explicitly change e to float64(e).

Another solution is: change printing verbs from %v to %g(for example), so that line 615 is invalid and subsequent v.Error() will never be called.

func (e ErrNegativeSqrt) Error() string {
	//return fmt.Sprintf("can't Sqrt negative number: %v\n", float64(e))
	return fmt.Sprintf("can't Sqrt negative number: %g\n", e)
}

In fact any verbs as listed below, except %x and %X, can do the trick.

 

2, Execise: Readers

package main

import (
	"golang.org/x/tour/reader"
)

type MyReader struct {}

func (r MyReader) Read(b []byte) (int, error) {
	n := cap(b)
	b = b[:n]
	for i := 0; i < n; i++ {
		b[i] = 'A'
	}

	return n, nil
}

func main() {
	reader.Validate(MyReader{})
}

 

3, Execise: rot13Reader

package main

import (
	"io"
	"os"
	"strings"
)

type rot13Reader struct {
	r io.Reader
}

func (rot13 *rot13Reader) Read(b []byte) (int, error) {
	size := cap(b)
	b = b[:size]

	n, err := rot13.r.Read(b)

	if err != nil {
		return 0, err
	}

	b = b[:n]
	for i := 0; i < n; i++ {
		if b[i] >= 'a' && b[i] <= 'z' {
			b[i] = 'a' + (b[i] - 'a' + 13) % 26
		}
		if b[i] >= 'A' && b[i] <= 'Z' {
			b[i] = 'A' + (b[i] - 'A' + 13) % 26
		}
	}

	return n, err
}

func main() {
	s := strings.NewReader("Lbh penpxrq gur pbqr!")
	r := rot13Reader{s}
	io.Copy(os.Stdout, &r)
}

Output looks like:

(18:36 dabs@CNU1343VF8 readers) > go build rot13reader.go && ./rot13reader
You cracked the code!(18:39 dabs@CNU1343VF8 readers) > 

Yeah, that's right, You cracked the code!

4, Execise: Images

package main

import (
	"image"
	"golang.org/x/tour/pic"
	"image/color"
)

type Image struct {
}

func (m Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 100, 100)
}

func (m Image) ColorModel() color.Model {
	return color.RGBAModel
}

func (m Image) At(x, y int) color.Color {
	v := uint8(x*y)
	return color.RGBA{v, v, 255, 255}
}

func main() {
	m2 := Image{}
	pic.ShowImage(m2)
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章