zoukankan      html  css  js  c++  java
  • golang中的结构体匿名成员

    最近在开发caddy的插件, 碰到了很多以前不怎么注意的地方, 先重点记录下几个点.

    写插件比较追求的一点是: 如何不破坏原有的体系而达到想要的效果. 这个确实有点难…

    结构体匿名成员

    有关结构体匿名成员在《Effective Go》中的embedding一节讲的很详细, 一言一蔽之: 另一种形式的继承. 如果B类型中包含了A类型的匿名成员, 则B类型的实例拥有(继承)了所有A类型实现的方法.

    看个简单的例子:

     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
    
    package main
    
    import "fmt"
    
    type I interface {
        Say()
        Run()
    }
    
    type XXX struct {
        Name string
    }
    
    func (x XXX) Say() {
        fmt.Printf("XXX name is: %s
    ", x.Name)
    }
    
    func (x XXX) Run() {
        fmt.Printf("XXX run away
    ")
    }
    
    type YYY struct {
        XXX
        Age int
    }
    
    func (y YYY) Say() {
        fmt.Printf("YYY name is: %s, age is: %d
    ", y.Name, y.Age)
    }
    
    func Play(p I) {
        p.Say()
        p.Run()
    
        _, ok := p.(XXX)
        if !ok {
            fmt.Printf("not xxx
    ")
        } else {
            fmt.Printf("is xxx
    ")
        }
    }
    
    func main() {
        x := &XXX{"x-aka-x"}
        y := &YYY{XXX: x, Age: 23}
    
        fmt.Printf("Play x
    ")
        Play(x)
        fmt.Printf("Play y
    ")
        Play(y)
    }

    这个小程序运行后会输出:

    1
    2
    3
    4
    5
    6
    7
    8
    
    === Play x
    XXX name is: x-aka-x
    XXX run away
    is xxx
    === Play y
    YYY name is: x-aka-x, age is: 23
    XXX run away
    not xxx

    利用这个特性我们可以很方便的在已有的实现上面实现我们个性化需求. 比如我们想在Play函数中调用Say()之前执行一些我们的逻辑, 我们可以很方便的通过写一个ZZZ类来继承YYY, 然后改写Say()方法来实现. 如果所有实现都根据接口来, 那没有任何问题, 但是总会碰到例外.

    type assertion

    上面的Play()函数中有这么一句_, ok := p.(XXX), 这个是将p尝试转换成XXX类型. 如果一个函数依赖特定类型进行处理, 那各个组建之间协调起来会比较麻烦. 我在caddy里面就遇到了类似的问题. caddy里面的插件是通过链式调用下一个模块的ServeHTTP(w http.ResponseWriter, r *http.Request)方法来实现的. 如果你的模块想在http响应头里面加一些自己的内容, 很容易联想到去实现http.ResponseWriter的接口, 然后我们可以直接继承caddy中的responseWriterWrapper类, 然后重写对应的WriteHeader(status int)方法. 这里有一个问题, 如果另外有个模块需要处理特定类型的w, 那么一旦你改变了对应的w, 则后续模块的功能都无法生效了. 原生的header插件与proxy插件就存在这么一个小问题.

    这个最好的解决办法是原生支持这么一个hook~

  • 相关阅读:
    有序矩阵中的第 k 个最小数组和
    查找和最小的K对数字
    前 K 个高频元素
    621. 任务调度器
    407. 接雨水 II
    c语言表达式求值 中缀表达式转后缀表达式 求值
    42. 接雨水
    MySQL高级特性——绑定变量
    MySQL高级特性之分区表
    MySQL优化特定类型的查询
  • 原文地址:https://www.cnblogs.com/ExMan/p/12124697.html
Copyright © 2011-2022 走看看