接口
Go语言是面向接口的,面向对象只支持封装,其余继承多态靠接口来实现的。
接口定义:使用者download------->实现者retriever
注意:接口由使用者定义(传统面向对象中:file实现文件的人告诉他人他实现了可读可写这两个接口)
接口的实现:是隐式的
接口变量:包括:实现者的类型、实现者的值 接口变量里面到底是值还是指针,可以选择。
接口变量自带指针:使用时候接口变量注意不要用&地址
接口变量同样采用值传递,几乎不需要使用接口的指针
指针接收者只能一指针方式使用,值接收者两者都可。
查看接口变量
Type Assertion
Type Switch
表示任何类型:interface{}
例子:比如queue中目前只能支持int类型
//只支持int类型 注意这里举例只列出了Push实际操作记得将Pop也修改
type Queue []int
func (q *Queue) Push(v int) {
*q = append(*q, v)
}
//支持任何类型
type Queue []interface{}
func (q *Queue) Push(v interface{}) {
*q = append(*q, v)
}
例子:1)如果只想支持int类型 2)例子:假如接口肚子都没限定类型,如何限定int
duck typing
并不是Go语言特有的
1)大黄鸭是鸭子吗?
传统类型系统:脊索动物门、脊椎动物亚门等 按此理来说不是鸭子(没有生命)
duck typing:像鸭子走路,长得像 等就是鸭子 (描述事务的外部行为而非内部结构)
总结:应该从实物角度而言,是不是鸭子。
2)go属于结构化类型系统,类似duck typing(需要动态绑定)。这里假设Go结构duck typing
3)其他语言中的duck typing
Python中的:
def download(retriever): return retriever.get("www.baidu.com") 注意:运行时候才知道传入的retriever有没有get
通常需要注释来说明接口
C++中的:本身就支持type typing 通过模板来支持
template <class R>
string download(const R& retriever) {
return retriever.get("www.baidu.com")
注意:编译时才知道传入的retriever有没有get
需要注释来说明接口(因为敲代码时候不知道)
Java中没有duck typing 类似代码是:
<R extends Retriever>
String download(R r){
return r.get("www.baidu.com");
}
注意:传入的参数必须实现Retriever接口 与Python与C++相比不需要注释说明
不是duck typing
问题:多个需求必须让R实现多个接口,这就有问题了
4)go语言中的:
同时需要Readable、Appendable怎么办?(Java的办法:apache polygene 思路就是把两个接口组装起来,非常难用)
同时具有Python、C++ 的duck typing灵活性(不需要注释),以及Java的类型检查
目录结构以及代码
main.go
package main import ( "fmt" "time" "learngo/retriever/mock" "learngo/retriever/real" ) //方法改名只影响到使用者 type Retriever interface { Get(url string) string //不需要加func } type Poster interface { Post(url string, form map[string]string) string } const url = "http://www.imooc.com" //如果不加http://会报错 //使用者 func download(r Retriever) string { return r.Get(url) } func post(poster Poster) { poster.Post(url, map[string]string{ "name": "ccmouse", "course": "golang", }) } //组合接口 type RetrieverPoster interface { Retriever Poster } func session(s RetrieverPoster) string { s.Post(url, map[string]string{ "contents": "another faked imooc.com", }) return s.Get(url) } func main() { var r Retriever //必须要去实现 mockretriever //r 肚子里究竟是什么? 一个类型,一个值(指针,或者拷贝的真实值) mockRetriever := mock.Retriever{ Contents: "this is a fake imooc.com"} r = &mockRetriever //值接收者可以去掉&,但是也可以加上 inspect(r) //真实的Retriver 指针接收者必须要&地址 r = &real.Retriever{ UserAgent: "Mozilla/5.0", TimeOut: time.Minute, }
//方法1 inspect(r) //方法2 // Type assertion 通过r.(*内容)来获得 可能会出错,为了防止出错加ok if mockRetriever, ok := r.(*mock.Retriever); ok { fmt.Println(mockRetriever.Contents) } else { fmt.Println("r is not a mock retriever") } fmt.Println( "Try a session with mockRetriever") fmt.Println(session(&mockRetriever)) //这里如果改为&retriever也可以 } //看看r肚子里面是什么东西 func inspect(r Retriever) { fmt.Println("Inspecting", r) fmt.Printf(" > Type:%T Value:%v\n", r, r) fmt.Print(" > Type switch: ") switch v := r.(type) { case *mock.Retriever: fmt.Println("Contents:", v.Contents) case *real.Retriever: fmt.Println("UserAgent:", v.UserAgent) } fmt.Println() }
mockretriever.go
package mock import "fmt" //名字最好不要用mockRetriever这样会重复 type Retriever struct { Contents string } //常用系统接口 相当于其他语言的toString func (r *Retriever) String() string { return fmt.Sprintf( "Retriever: {Contents=%s}", r.Contents) } //实现者还想实现Post方法 指针接收者 func (r *Retriever) Post(url string, form map[string]string) string { r.Contents = form["contents"] return "ok" } //语言本身不需要说明 只需要实现Get方法即可 func (r *Retriever) Get(url string) string { return r.Contents }
retriever.go
package real import ( "net/http" "net/http/httputil" "time" ) //真实的Retriever type Retriever struct { UserAgent string TimeOut time.Duration //一个时间段 } func (r *Retriever) Get(url string) string { resp, err := http.Get(url) if err != nil { panic(err) } result, err := httputil.DumpResponse( resp, true) resp.Body.Close() //读完了之后要去close它 if err != nil { panic(err) } return string(result) }
输出
Inspecting Retriever: {Contents=this is a fake imooc.com} > Type:*mock.Retriever Value:Retriever: {Contents=this is a fake imooc.com} > Type switch: Contents: this is a fake imooc.com Inspecting &{Mozilla/5.0 1m0s} > Type:*real.Retriever Value:&{Mozilla/5.0 1m0s} > Type switch: UserAgent: Mozilla/5.0 r is not a mock retriever Try a session with mockRetriever another faked imooc.com Process finished with exit code 0
常用系统接口
Stringer 相当于其他语言的toString
type Stringer interface { String() string }
Reader 接口 Writer接口 :对文件的抽象 其实不一定是文件可以是其他的
type Reader interface { Read(p []byte) (n int , err error) }
type Writer interface {
Write(p []byte) (n int , err error)
}
接口的组合:
type ReadWriter interface { Reader Writer }