From eaa4c89ef001368b936380702779e34c0bab4d96 Mon Sep 17 00:00:00 2001 From: leisore Date: Mon, 31 Aug 2015 14:09:42 +0800 Subject: [PATCH] CH11.6 OK --- eBook/11.5.md | 2 +- eBook/11.6.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++ eBook/directory.md | 1 + 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 eBook/11.6.md diff --git a/eBook/11.5.md b/eBook/11.5.md index d9ad216..b9bbcf4 100644 --- a/eBook/11.5.md +++ b/eBook/11.5.md @@ -26,4 +26,4 @@ if sv, ok := v.(Stringer); ok { - [目录](directory.md) - 上一章:[11.4 类型判断:type-switch](11.4.md) -- 下一节:[11.6 TODO](11.6.md) \ No newline at end of file +- 下一节:[11.6 使用方法集与接口](11.6.md) \ No newline at end of file diff --git a/eBook/11.6.md b/eBook/11.6.md new file mode 100644 index 0000000..5f3f40e --- /dev/null +++ b/eBook/11.6.md @@ -0,0 +1,92 @@ +# 11.6 使用方法集与接口 + +在 10.6.3 及例子 methodset1.go 中我们看到,作用于变量上的方法实际上是不区分变量到底是指针还是值的。当碰到接口类型值时,这会变得有点复杂,原因是接口变量中存储的具体值是不可寻址的,幸运的是,如果使用不当编译器会给出错误。考虑下面的程序: + +示例 11.5 methodset2.go: + +```go +package main + +import ( + "fmt" +) + +type List []int + +func (l List) Len() int { + return len(l) +} + +func (l *List) Append(val int) { + *l = append(*l, val) +} + +type Appender interface { + Append(int) +} + +func CountInto(a Appender, start, end int) { + for i := start; i <= end; i++ { + a.Append(i) + } +} + +type Lener interface { + Len() int +} + +func LongEnough(l Lener) bool { + return l.Len()*10 > 42 +} + +func main() { + // A bare value + var lst List + // compiler error: + // cannot use lst (type List) as type Appender in argument to CountInto: + // List does not implement Appender (Append method has pointer receiver) + // CountInto(lst, 1, 10) + if LongEnough(lst) { // VALID:Identical receiver type + fmt.Printf("- lst is long enough\n") + } + + // A pointer value + plst := new(List) + CountInto(plst, 1, 10) //VALID:Identical receiver type + if LongEnough(plst) { + // VALID: a *List can be dereferenced for the receiver + fmt.Printf("- plst is long enough\n") + } +} +``` + +**讨论** + +在 `lst` 上调用 `CountInto` 时会导致一个编译器错误,因为 `CountInto` 需要一个 `Appender`,而它的方法 `Append` 只定义在指针上。 在 `lst` 上调用 `LongEnough` 是可以的因为 'Len' 定义在值上。 + +在 `plst` 上调用 `CountInto` 是可以的,因为 `CountInto` 需要一个 `Appender`,并且它的方法 `Append` 定义在指针上。 在 `plst` 上调用 `LongEnough` 也是可以的,因为指针会被自动解引用。 + +**总结** + +在接口上调用方法时,必须有和方法定义时相同的接收者类型或者是可以从具体类型 `P` 直接可以辨识的: + +- 指针方法可以通过指针调用 +- 值方法可以通过值调用 +- 接收者是值的方法可以通过指针调用,因为指针会首先被解引用 +- 接收者是指针的方法不可以通过值调用,因为存储在接口中的值没有地址 + +将一个值赋值给一个接口赋值时,编译器会确保所有可能的接口方法都可以在此值上被调用,因此不正确的赋值在编译期就会失败。 + + +译注: + +Go语言规范定义了接口方法集的调用规则: + +- 类型 *T 的可调用方法集包含接受者为 *T 或 T 的所有方法集 +- 类型 T 的可调用方法集包含接受者为 T 的所有方法 +- 类型 T 的可调用方法集不包含接受者为 *T 的方法 + + +- [目录](directory.md) +- 上一章:[11.5 测试一个值是否实现了某个接口](11.5.md) +- 下一节:[11.7 第一个例子:使用Sorter接口排序](11.7.md) \ No newline at end of file diff --git a/eBook/directory.md b/eBook/directory.md index 6a8412a..25b3453 100644 --- a/eBook/directory.md +++ b/eBook/directory.md @@ -99,6 +99,7 @@ - 11.3 [绫诲瀷鏂█锛氬浣曟娴嬪拰杞崲鎺ュ彛鍙橀噺鐨勭被鍨媇(11.3.md) - 11.4 [绫诲瀷鍒ゆ柇锛歵ype-switch](11.4.md) - 11.5 [娴嬭瘯涓涓兼槸鍚﹀疄鐜颁簡鏌愪釜鎺ュ彛](11.5.md) + - 11.6 [浣跨敤鏂规硶闆嗕笌鎺ュ彛](11.6.md) ## 绗笁閮ㄥ垎锛欸o 楂樼骇缂栫▼