duanjiaopi8218 2019-06-18 10:01
浏览 56

类型实现中的隐藏方法?

Going through some go sources in the net/http and related libraries, I came across something that made me curious. I'm looking at version 1.12 here.

func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.Request, res *http.Response) {
  ...
  hj, ok := rw.(http.Hijacker)
  ...
  conn, brw, err := hj.Hijack()
  ...
}

I've been seeing stuff like this in more places and also outside the standard library. What is happening here? Are some methods of an interface implementation hidden until a specific assertion happens? Why can't I just call Hijack() on the rw object?

  • 写回答

1条回答 默认 最新

  • douchui7332 2019-06-18 10:01
    关注

    The methods appear to be hidden, because the function takes an interface type. The interface of http.ResponseWriter does not define the Hijack() method. This is defined in the http.Hijacker interface. A concrete type may implement multiple interfaces. But even if such concrete type is passed into a scope where its type definition is an interface, additional methods will not be accessible. So in the questioned example, type assertion is performed to make make the Hijack() method available.

    Some examples (playground):

    package main
    
    import (
        "fmt"
    )
    
    type Ship interface {
        Load(containers []string)
        Condition() []string
    }
    
    type Sea interface {
        Draft() int
    }
    
    // seaShip implements the Sea and Ship interfaces
    type seaShip struct {
        containers []string
    }
    
    // Load is only part of the Ship interface
    func (ss *seaShip) Load(containers []string) {
        ss.containers = append(ss.containers, containers...)
    }
    
    // Condition is only part of the Ship interface
    func (ss *seaShip) Condition() []string {
        return ss.containers
    }
    
    // Draft is only part of the Sea interface
    func (ss *seaShip) Draft() int {
        return len(ss.containers)
    }
    
    // Pirates is not defined in any interface and therefore can only be called on the concrete type
    func (ss *seaShip) Pirates() string {
        return "Help!"
    }
    
    // NewShip returns an implementation of the Ship interface
    func NewShip() Ship {
        return &seaShip{}
    }
    
    func main() {
        ship := NewShip()
        ship.Load([]string{"Beer", "Wine", "Peanuts"})
        fmt.Println(ship.Condition())
        // Won't compile, method is not part of interface!
        // fmt.Println(ship.Draft())
    
        // Assert to make Draft() available
        sea := ship.(Sea)
        fmt.Println(sea.Draft())
    
        // Won't compile, methods are not part of interface!
        // fmt.Println(sea.Condition())
        // fmt.Println(sea.Pirates())
    
        // Assert to the concrete type makes all methods available
        ss := sea.(*seaShip)
        fmt.Println(ss.Condition())
        fmt.Println(ss.Pirates())
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 在获取boss直聘的聊天的时候只能获取到前40条聊天数据
  • ¥20 关于URL获取的参数,无法执行二选一查询
  • ¥15 液位控制,当液位超过高限时常开触点59闭合,直到液位低于低限时,断开
  • ¥15 marlin编译错误,如何解决?
  • ¥15 有偿四位数,节约算法和扫描算法
  • ¥15 VUE项目怎么运行,系统打不开
  • ¥50 pointpillars等目标检测算法怎么融合注意力机制
  • ¥20 Vs code Mac系统 PHP Debug调试环境配置
  • ¥60 大一项目课,微信小程序
  • ¥15 求视频摘要youtube和ovp数据集