Golang Interface 应用 Interface是什么? 在Golang中,interface是一组method的集合,duck-type programing的一种体现。不关心属性(数据),只关心行为(方法)。可以认为interface是一种协议,一种为了双方交流而做出的约定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type error interface { Error() string } type MyErr struct {}func (e *MyErr) Error() string { return "my error" }
Interface能干什么?
writing generic algorithm (泛型编程)
hiding implementation detail (隐藏具体实现)
providing interception points (提供拦截点)
writing generic algorithm golang的泛型最早1.17才提供版本支持。用interface实现一下行不行呀?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package sorttype Interface interface { Len() int Less(i, j int ) bool Swap(i, j int ) } type BestLanguage struct { Name string Score int } func (b BestLanguage) String() string { return fmt.Sprintf("%s:%d" , b.Name, b.Score) } type Languages []BestLanguagefunc (l Languages) Len() int { return len (Languages{}) } func (l Languages) Less(i, j int ) bool { return l[i].Score > l[j].Score } func (l Languages) Swap(i, j int ) { l[i], l[j] = l[j], l[i] } func main () { languages := []BestLanguage{ {"Chinese" , 5 }, {"English" , 4 }, {"Japanese" , 3 }, } fmt.Println(languages) sort.Sort(Languages(languages)) fmt.Println(languages) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func ConvertInterfaceToString (v interface {}) string { var vstr string switch v.(type ) { case int : vstr = strconv.Itoa(v.(int )) case int32 : vstr = strconv.Itoa(int (v.(int32 ))) case int64 : vstr = strconv.FormatInt(v.(int64 ), 10 ) case float64 : vstr = strconv.Itoa(int (v.(float64 ))) case string : vstr = v.(string ) default : } return vstr }
hiding implement detail 三个函数返回的具体 struct (都实现了 Context interface),但是对于使用者来说是完全无感知的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 type Context interface { Deadline() (deadline time.Time, ok bool ) Done() <-chan struct {} Err() error Value(key interface {}) interface {} } type cancelCtx struct { Context mu sync.Mutex done chan struct {} children map [canceler]struct {} err error } func WithCancel (parent Context) (ctx Context, cancel CancelFunc) type timerCtx struct { cancelCtx timer *time.Timer deadline time.Time } func WithDeadline (parent Context, deadline time.Time) (Context, CancelFunc) type valueCtx struct { Context key, val interface {} } func WithValue (parent Context, key, val interface {}) Context
providing interception points 实现RoundTripper接口,可以在http请求前后写入自己的逻辑,如apm,jaeger的打点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package httptype RoundTripper interface { RoundTrip(*Request) (*Response, error ) } func WrapClient (c *http.Client) *http.Client { if c == nil { c = http.DefaultClient } copied := *c copied.Transport = wrapRoundTripper(copied.Transport) return &copied } func wrapRoundTripper (r http.RoundTripper) http.RoundTripper { if r == nil { r = http.DefaultTransport } rt := &roundTripper{r: r} return rt } type roundTripper struct { r http.RoundTripper } func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error ) { resp, err := r.r.RoundTrip(req) return resp, err }
值接收 or 指针接收 实现接口的时候应该用值还是指针?
赋值时必须用指针。
初始化为指针类型,编译指定没问题。
❎表示编译不通过,因为对象没有声明接口的全部方法。
指针类型没有声明全部,但是能编译通过,因为Go自己做了一些转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 type Animal interface { Eat(food string ) Say() } type Dog struct { food string } func (d Dog) Eat(food string ) { d.food = food } func (d Dog) Say() { fmt.Println("dog like " , d.food) } type Cat struct { food string } func (d *Cat) Eat(food string ) { d.food = food } func (d *Cat) Say() { fmt.Println("cat like " , d.food) } type Fish struct { food string } func (d *Fish) Eat(food string ) { d.food = food } func (d Fish) Say() { fmt.Println("fish like " , d.food) } func main () { var dog Animal = Dog{} var dog Animal = &Dog{} var dog Animal = new (Dog) dog.Eat("bone" ) dog.Say() ❎ var cat Animal = Cat{} var cat Animal = new (Cat) cat.Eat("fish" ) cat.Say() ❎ var fish Animal = Fish{} var fish Animal = new (Fish) fish.Eat("small fish" ) fish.Say() }
参考 http://legendtkl.com/2017/06/12/understanding-golang-interface/