覆盖接口的函数回调参数

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

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

controllers / auth.go:52:17:不能在c.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)

2 years ago

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

Group(fn func(r Router)) Router

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

func(r Router)

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

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

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

func(r router.Router)

那个's not the signature required by the method you'正在调用,所以如果 router.Router 实现 chi.Router ,它就会赢得't compile. It doesn';传递的参数(a func(router.Router) )不是预期的类型( func(chi.Router) ) .

这一开始可能看起来很愚蠢 - 毕竟,任何 router.Router 都必须实施 chi.Router . 但是,考虑一下:那个方法 Group 期待接收一个函数,它可以传递给任何函数 chi.Router . 这意味着它可以传递 chi.Router ,它不实现 router.Router . 如果要接受你的函数,它会破坏类型安全性,而Go中的内容是编译时错误(错误是你希望保证该方法永远不会提供的) .

2 years ago

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