自用留存
duck typing
- 像鸭子走路,像鸭子叫,长得像鸭子,那么就是鸭子
- 描述事物的外部行为而非内部结构
- 和一个人或者事务互动,不管是什么人,什么事务,只要提供指定能力,我们与能力互动
- 严格说go属于结构化类型系统,类似duck typing
python
def download(retriever):
return retriever.get("www.baidu.com")
- 运行时 才知道传入的retriever有没有get
- 需要注释来说明接口
c++
template <class R>
string download(const R& retriever) {
return retriever.get("www.baidu.com");
}
- 编译时才知道传入的retriever有没有get
- 需要注释来说明接口
java
<R extends Retriever>
String download(R r) {
return r.get("www.baidu.com")
}
- 传入参数必须实现Retriever接口
- 不是duck typing
go
type Retiever interface {
Get(url string) string
}
func download(r Retiever) string {
return r.Get("www.baidu.com")
}
- 同时具有python,c++的duck typing的灵活性
- 又具有java类型的检查
go接口定义和实现:
使用者
–>实现者
- 接口由使用者定义
- 接口实现是隐式的
- 只要实现接口里面的方法
package main
import (
"awesome/mock"
"awesome/retr"
"fmt"
)
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 fake baidu"}
r = retr.Retriever{}
fmt.Println(download(r))
}
package retr
import (
"net/http"
"net/http/httputil"
"time"
)
type Retriever struct {
UserAgent string
TimeOut time.Duration
}
func (receiver Retriever) Get(url string) string {
resp, err := http.Get(url)
if err != nil {
panic(err)
}
result, err := httputil.DumpResponse(resp, true)
resp.Body.Close()
if err != nil {
panic(err)
}
return string(result)
}
package mock
type Retriever struct {
Contents string
}
func (r Retriever) Get(url string) string {
return r.Contents
}
go接口的值类型
package main
import (
"awesome/mock"
"awesome/retr"
"fmt"
)
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 fake baidu"}
fmt.Printf("%T %v\n", r, r)
r = retr.Retriever{}
fmt.Printf("%T %v\n", r, r)
//fmt.Println(download(r))
}
//mock.Retriever {this is fake baidu}
//retr.Retriever { 0s} //package retr 中 Retriever struct 第一个值默认是空,time默认是0s
package main
import (
"awesome/mock"
"awesome/retr"
"fmt"
"time"
)
type Retriever interface {
Get(url string) string
}
func download(r Retriever) string {
return r.Get("https://www.baidu.com")
}
func main() {
r := retr.Retriever{
"Google29", //UserAgent string
time.Hour, //TimeOut time.Duration
}
fmt.Printf("%T %v\n", r, r)
}
//retr.Retriever {Google29 1h0m0s}
package retr
import (
-
)
type Retriever struct {
UserAgent string
TimeOut time.Duration
}
func (receiver *Retriever) Get(url string) string { //指针
...
}
-----------------------------------------------------
package main
import (
...
)
type Retriever interface {
...
}
func download(r Retriever) string {
...
}
func main() {
...
r = &retr.Retriever{ //获取指针
...
}
fmt.Printf("%T %v\n", r, r)
//fmt.Println(download(r))
}
//*retr.Retriever &{Google29 1h0m0s}//类型是指针类型 *retr.Retriever 值是指针 &{Google29 1h0m0s}
func inspect(r Retriever) {
switch v := r.(type) {
case mock.Retriever:
fmt.Println("contents:", v.Contents)
case *retr.Retriever:
fmt.Println("UserAgent:", v.UserAgent)
}
}
//*retr.Retriever &{Google29 1h0m0s}
//UserAgent: Google29
func main() {
...
//type assertion
if realRetriever, ok := r.(*retr.Retriever); ok {
fmt.Println(realRetriever.TimeOut)
} else {
fmt.Println("not a retr retriever")
}
}
//1h0m0s //默认1h
接口变量里面有什么
- 接口变量自带指针
- 接口变量同样采用值传递,几乎不需要使用接口的指针
- 指针接收者实现只能以指针方式使用;值接收者即可
查看接口变量
- 表示任何类型 :interface{}
- type Assertion
- Type Switch
go接口组合
package main
import (
"awesome/mock"
"awesome/retr"
"fmt"
"time"
)
type Retriever interface {
Get(url string) string
}
type Poster interface {
Post(url string, form map[string]string) string
}
func post(poster Poster) {
poster.Post("https://www.baidu.com", map[string]string{
"name": "baidu",
"lang": "go",
})
}
type RetrieverPoster interface {
Retriever
Poster
}
func session(s RetrieverPoster) string {
s.Post(url, map[string]string{
"contents": "show this is true",
})
return s.Get(url)
}
const url = "https://www.baidu.com"
func download(r Retriever) string {
return r.Get("https://www.baidu.com")
}
func main() {
var r Retriever
retriever := mock.Retriever{"show this is false"}
r = &retriever
//type assertion
if mockRetriever, ok := r.(*mock.Retriever); ok {
fmt.Println(mockRetriever.Contents)
} else {
fmt.Println("not a mock retriever")
}
fmt.Println("try a session")
fmt.Println(session(&retriever))
}
//try a session
//show this is true
-----------------------------------
package mock
type Retriever struct {
Contents string
}
func (r *Retriever) Post(url string, form map[string]string) string {
//TODO implement me
r.Contents = form["contents"]
return "ok"
}
func (r *Retriever) Get(url string) string {
return r.Contents
}
-------------------------------------
package retr
import (
"net/http"
"net/http/httputil"
"time"
)
type Retriever struct {
UserAgent string
TimeOut time.Duration
}
func (receiver *Retriever) Get(url string) string {
resp, err := http.Get(url)
if err != nil {
panic(err)
}
result, err := httputil.DumpResponse(resp, true)
resp.Body.Close()
if err != nil {
panic(err)
}
return string(result)
}
特殊接口
stringer()
io.Reader()
io.Writer()
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func printFile(filename string) {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
printFileContents(file)
}
func printFileContents(reader io.Reader) {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
func main() {
printFile("testdoc.txt")
s := `abcde"qwe"
asd
ffff`
printFileContents(strings.NewReader(s))
}
/*
文本内容
abcde"qwe"
asd
ffff
*/