覆盖接口的函数回调参数

时间:2018-03-08 01:19:47

标签: go

我正在使用一个具有Router接口的软件包,我创建了自己的特定于应用程序的Router接口,用于包装第三方软件包。

一切都运行良好,但其中一种方法是抛出编译错误:

  

controllers / auth.go:52:17:不能在f.router.Group的参数中使用func文字(类型为func(router.Router))作为类型func(chi.Router)

这是第三方包(chi)的界面:

type Router interface {
    // ...

    // Group adds a new inline-Router along the current routing
    // path, with a fresh middleware stack for the inline-Router.
    Group(fn func(r Router)) Router

    // ...
}

这是我的包装界面:

type Router interface {
    chi.Router

    // Custom methods...
}

我对Group函数的使用是这样的:

type AuthController struct {
    router router.Router
    // ...
}

func (c *AuthController) SetRoutes() {
    c.router.Group(func(r router.Router) {
        r.Use(middleware.Anyone)

        r.Post("/auth/register", c.Register)
        r.Post("/auth/login", c.Authenticate)
        r.Post("/auth/token/refresh", c.RefreshToken)
    })

    c.router.Group(func(r router.Router) {
        r.Use(middleware.Authorized)

        r.Get("/auth/ping", c.Ping)
        r.Post("/auth/logout", c.Logout)
    })
}

为什么它在我的函数回调参数类型中尖叫?我的包装器router.Router实现了chi.Router接口,所以它不应该正常工作吗?我误解了Go如何在这里工作吗?

2 个答案:

答案 0 :(得分:2)

参数类型不相同,因此函数类型与预期的不匹配,即使您的接口包含来自其他包的接口(类型必须完全匹配)。您需要让函数采用chi.router,然后使用类型断言(即myRouter := r.(Router))转换为您的类型。

答案 1 :(得分:1)

我可以看到这会让人感到困惑,所以我会尝试将其分解。你有这个方法:

Group(fn func(r Router)) Router

此方法将函数作为参数。该功能必须具有特定的签名:

func(r Router)

也就是说,它只需要chi.Router类型的单个参数,并且没有返回值。但是,当你打电话时:

c.router.Group(func(r router.Router) { /***/ }

你传递了错误签名的功能;你的功能签名是:

func(r router.Router)

这不是您正在调用的方法所需的签名,因此无法编译。如果router.Router实现chi.Router,则无关紧要;传递的参数(a func(router.Router))不是预期的类型(func(chi.Router))。

这一开始可能看起来很愚蠢 - 毕竟,任何router.Router都必须实施chi.Router。但是,请想一想:该方法Group期望接收一个函数,它可以传递任何 chi.Router。这意味着它可以传递未实现的chi.Router router.Router。如果要接受你的函数,它会破坏类型的安全性,而Go中的内容是编译时错误(实际上你得到的错误)将成为运行时错误。基本上,通过传递具有不同(和更严格)参数类型的函数,您期望保证该方法从未提供过。