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