Learning Go - 4 Methods and Interfaces
1. 方法
func (v *Vertex) Abs() float64 { // 可以在结构体类型上定义方法,func和方法名中间
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
v.Abs() // 这么调用
type MyFloat float64 // 任意类型都可以定义方法,但是要type一下
func (f MyFloat) Abs() float64 {...}
// 接收者为指针:避免在每个方法调用中拷贝,更有效率;方法可以修改接收者指向的值,否则修改副本没有用
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
2. 接口
type Abser interface { // 一组方法定义的集合
Abs() float64
}
var a Abser // a可以赋值:实现这些方法如Abs()的任何值
// 例子
type Person struct {
Name string
Age int
}
func (p Person) String() string { //`fmt`包使用接口Stringer中的String()方法来进行输出
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
fmt.Println(a) // Arthur Dent (42 years), 相当于 重载了cout
}
3. 异常
i, err := strconv.Atoi("42")
if err != nil { // 非空表示失败
fmt.Printf("couldn't convert number: %v\n", err)
}
fmt.Println("Converted integer:", i)
Exercise - error: 实现Sqrt使其接收到一个负数时,返回一个非nil错误值
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
return "cannot Sqrt negative number:" + fmt.Sprint(float64(e))
}
func Sqrt(x float64) (float64, error) {
if(x < 0) {
return x, ErrNegativeSqrt(x)
}
z := float64(1)
for {
y := (z + x/z) / 2.0
fmt.Println(y)
if math.Abs(z - y) < 1e-10 {
break
}
z = y
}
return z, nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2)) // fmt包在输出时也会试图匹配 error接口
}
4. io.Reader接口
r := strings.NewReader("Hello, Reader!") // 创建Reader
b := make([]byte, 8) // 每次读取8字节
for {
n, err := r.Read(b) // Reader接口中的Read方法
fmt.Printf("n = %v err = %v b = %v\n", n, err, b) // 8 nil;6 nil;0 EOF
fmt.Printf("b[:n] = %q\n", b[:n]) // %q, 打印字符串
if err == io.EOF { // 遇到数据流结尾时返回
break
}
}
Exercise - rot13Reader: io.Reader包裹另一个io.Reader
type rot13Reader struct {
r io.Reader
}
func (rr rot13Reader) Read(s []byte) (n int, e error) {
n, e = rr.r.Read(s)
for i := 0; i < n; i++ {
if((s[i]>='a'&&s[i]<'n') || (s[i]>='A'&&s[i]<'N')) {
s[i] += 13
} else {
s[i] -= 13
}
}
return //可以省略
}
func main() {
s := strings.NewReader("Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
5. Web Server
包http通过任何实现了http.Handler接口的值来响应HTTP请求, 如其中的ServeHTTP函数
import (
"log"
"net/http"
"fmt"
)
type String string
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, s)
}
type Struct struct { // 各种类型都可以实现该接口
Greeting string
Punct string
Who string
}
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, s.Greeting, s.Punct, s.Who)
}
func main() {
http.Handle("/string", String("I'm a frayed knot."))
http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
http.ListenAndServe("localhost:4000", nil)
}