duck typing
许多编程语言都支持 Duck Typing ,通常 Duck Typing 是动态编程语言用来实现多态的一种方式
Duck Typing 的原话是,走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么它就是一只鸭子。描述事物的外部行为而非内部结构
Demo
-
Python
def download(retriever): return retriever.get("www.imooc.com")
运行时才知道传入的
retriever
有没有get
; 需要注释来说明接口 -
c++
template <class R> string download(const R& retriver) { retrun retriever.get("www.imooc.com"); }
编译时才知道传入的
retriever
有没有get
; 需要注释来说明接口 -
java
java
是没有duck typing
, 有类似的<R extends Retriver> String download(R r) { return r.get("www.imooc.com") }
传入的参数必须实现
Retriever
接口; 不是duck typing
-
go
在
java
的duck typing
type R interface { Get(url string) string }
接口
定义
package mock
type Retriever stuct {
Contents string
}
func (r Retriever) Get(url string) string {
return r.Contents
}
-
接口由使用者定义
// 定义接口 type Retriever interface { Get(url string) string } // 使用 func download(r Retriever) string {\ return r.Get("https://www.baidu.com") }
-
接口实现是隐式的
func main() { var r Retriever // 调用接口 r = mock.Retriever("this is hello") }
只要实现接口里的方法
接口的值类型
打印出类型, 和 value
func main() {
var r Retriever
// 调用接口
r = mock.Retriever("this is hello")
fmt.Printf("%T %v\n", r, r) // 结果 mock.Retriever {this is hello }
}
-
接口变量里有什么
- 接口变量自带指针
- 接口变量同样采用值传递, 几乎不需要使用接口的指针
接口变量
- 表示任何类型: interface{}
- Type Assertion
- Type Switch
接口组合
可以将多个接口组合成一个新的接口, 然后通过组合后的接口, 调用里面每个接口元素的方法
// 接口一
type Retriever interface {
Get(url string) string
}
// 接口二
type Poster interface {
Post(url string, form map[string]string) string
}
// 接口组合
type RetrieverPoster interface {
Retriever
Poster
}
// 调用
func session(s RetrieverPoster) string {
s.Post(url, map[string]string{
"contents" : "hello duck typing"
})
return s.Get(url)
}
常用系统接口
-
Stringer
方法被用于打印传递的值, 格式和未格式化的字符串打印
-
Reader
Reader 实现了 io.Reader、io.ReaderAt、io.ByteReader、io.ByteScanner、
io.RuneReader、io.RuneScanner、io.Seeker 和 io.WriterTo 通过读取接口
从一个字符串。
Reader 的零值的操作类似于空字符串的 Reader。func printFileContents(reader io.Reader) { scanner := bufio.NewScanner(reader) for scanner.Scan() { fmt.Println(scanner.Text()) } }
-
Writer
Writer 是封装了基本 Write 方法的接口。
Write 将 len(p) 个字节从 p 写入底层数据流。
它返回从 p (0 <= n <= len(p)) 写入的字节数
以及任何导致写入提前停止的错误。
如果 Write 返回 n < len(p),则它必须返回一个非 nil 错误。
写入不得修改切片数据,即使是临时修改。