Golang中的方法与接口

方法

Go虽然没有类,但是可以在struct上定义方法。

package main

import (
	"fmt"
	"math"
)

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) Show(what string) {
	fmt.Println("show ", what)
}

func main() {
	v := &Vertex{3, 4}
	fmt.Println(v.Abs())
	v.Show("me")
}

其实,只要在你的包里声明的任何类型都可以定义方法

package main

import (
	"fmt"
	"math"
)

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())
}

通常方法是绑在指针上,这样避免了在传参的时候复制,也便于方法直接修改指针所指向的值。

接口

接口类型是一个包含一组方法定义的集合。也就是接口里定义了一组方法。

只要一个类型实现了这个接口了的方法,就能赋给这个接口类型。

package main

import (
	"fmt"
	"math"
)

type Abser interface {
	Abs() float64
}

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())
}

type MyFloat float64

func (f MyFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type Vertex struct {
	X, Y float64
}

func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

exercise-stringer.go

这是对fmt包里的Stringer接口的使用,实现了他里面定义的String() string方法.

Stringer是一个用string描述自己的接口

package main

import "fmt"

type IPAddr [4]byte

// TODO: Add a "String() string" method to IPAddr.
func (x IPAddr) String() string {
	return fmt.Sprintf("%d.%d.%d.%d", x[0],x[1],x[2],x[3]);
}

func main() {
	addrs := map[string]IPAddr{
		"loopback":  {127, 0, 0, 1},
		"googleDNS": {8, 8, 8, 8},
	}
	for n, a := range addrs {
		fmt.Printf("%v: %v\n", n, a)
	}
}

Error

与fmt.Stringer类似,error类型是一个内建接口.

type error interface {
	Error() string
}

通常函数会返回一个 error 值,调用的它的代码应当判断这个错误是否等于 nil, 来进行错误处理。

i, err := strconv.Atoi(“42”) if err != nil { fmt.Printf(“couldn’t convert number: %v\n”, err) } fmt.Println(“Converted integer:“, i) error 为 nil 时表示成功;非 nil 的 error 表示错误。

exercise-errors.go

package main

import (
	"fmt"
)

type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

func Sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, ErrNegativeSqrt(x)
	}
	z := x
	for i := 0; i < 10; i++ {
		z = z - (z * z - x)/(2*z)
	}
	return z, nil
}



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

exercise-rot-reader.go

这个开始没有读入到io.Reader…坑了半天

package main

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

type rot13Reader struct {
	r io.Reader
}

func (rot *rot13Reader) Read(bytes []byte) (int, error) {
	n, err := rot.r.Read(bytes)
	s := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzNOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"
	for index := range bytes {
		if !((bytes[index] >= 'a' && bytes[index] <='z') || (bytes[index] >= 'A' && bytes[index] <='Z')){
			continue
		}
		pos := strings.IndexByte(s, bytes[index])
		bytes[index] = s[pos + 26*2]
	}
	return n, err
}

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

web servers

http包为任何实现了http.Handler接口的值提供服务

package http

type Handler interface {
    ServeHTTP(w ResponseWriter, r *Request)
}

官网的例子:

package main

import (
	"fmt"
	"log"
	"net/http"
)

type Hello struct{}

func (h Hello) ServeHTTP(
	w http.ResponseWriter,
	r *http.Request) {
	fmt.Fprint(w, "Hello!")
}

func main() {
	var h Hello
	err := http.ListenAndServe("localhost:4000", h)
	if err != nil {
		log.Fatal(err)
	}
}

exercise-http-handlers.go

package main

import (
		"fmt"
		"log"
		"net/http"
	   )

type String string

type Struct struct {
	Greeting	string
		Punct		string
		Who			string
}

func (str String) ServeHTTP(
		w http.ResponseWriter,
		r *http.Request) {
	fmt.Fprint(w, str)
}

func (stu *Struct) ServeHTTP(
		w http.ResponseWriter,
		r *http.Request) {
	fmt.Fprint(w,fmt.Sprintln(stu.Greeting, stu.Punct, stu.Who))
}

func main() {
	// your http.Handle calls here
	http.Handle("/string", String("I'm a frayed knot."))
	http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
	log.Fatal(http.ListenAndServe("localhost:4000", nil))
}

excercise-images.go

package main

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

type Image struct{
	w, h int
	colr uint8
}

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

func (IMG Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 200, 200)
}

func (IMG Image) At(x, y int) color.Color {
	return color.RGBA{uint8(x), uint8(y), 255,255}
}

func main() {
	m := Image{100,100,200}
	pic.ShowImage(m)
}