简体   繁体   English

前往:反思catch22反思套餐

[英]Go: Reflection catch22 reflect package

Ok.. I have, or am writing a web framework package, called mao. 好的,我已经或正在编写一个名为mao的Web框架程序包。

I'd like to have my Route defined in the controller. 我想在控制器中定义我的路线。

in mao 在毛

type (
    Controller struct {
        Route Route
    }
    Route struct {
        Name, Host, Path, Method string
    }
)

in mao importing package 在毛进口包中

controller/default.go 控制器/ default.go

type DefaultController struct {
    mao.Controller
}
func (this *DefaultController) Index() Response {
    this.Route = mao.Route{"default_index","localhost","/", "GET"}
}

Now since I'd like to define my route inside the controller, the router, when instanced should read all controllers. 现在,由于我想在控制器内部定义路由,因此路由器在实例化时应读取所有控制器。 That's the problem. 那就是问题所在。

How do I pass the package name to my router so it's able to get all structs and functions in that package? 如何将程序包名称传递给路由器,以便能够获取该程序包中的所有结构和功能? Is it even possible? 可能吗?

What you ask isn't possible in Go, since it doesn't have a way to enumerate all types in a package/program. 您无法在Go中进行查询,因为它无法枚举包/程序中的所有类型。

One alternative would be to follow the lead of the database/sql package, and have a system where other packages can register with it when imported. 一种选择是跟随database/sql程序包的database/sql ,并具有一个系统,其他程序包可以在导入时向其注册。

For example, to use the PostgreSQL driver with that package, you might do: 例如,要将PostgreSQL驱动程序与该软件包一起使用,您可以这样做:

import (
    _ "github.com/lib/pq"
    "database/sql"
)

...
db, err := sql.Open("postgres", "dbname=test")

The postgres driver is registered during initialisation of the github.com/lib/pq package. 在初始化github.com/lib/pq软件包期间注册了postgres驱动程序。 Here is the relevant code from that package (eliding some parts that aren't relevant): 这是该软件包中的相关代码(省略了一些不相关的部分):

package pq

import (
    "database/sql"
)

type drv struct{}

func (d *drv) Open(name string) (driver.Conn, error) {
    return Open(name)
}

func init() {
    sql.Register("postgres", &drv{})
}

Perhaps you could create a registration API like this to find the various implementations available in the program? 也许您可以创建这样的注册API来找到程序中可用的各种实现?

Honestly, I think you are doing it the wrong way. 老实说,我认为您的做法是错误的。 "auto registering" is obfuscating what happens and will lead to code that is hard to test and to reason about. “自动注册”使发生的事情难以理解,并导致难以测试和推理的代码。

I would suggest to make controller an interface that should be satisfied by the concrete controllers and have a method Add(c Controller) on the router to assign the controller in the calling main project (that imports the router and the controllers). 我建议使控制器成为具体控制器应满足的接口,并在路由器上具有Add(c Controller)方法,以在调用主项目(导入路由器和控制器)中分配控制器。 This should make your code understandable and explicit and is more in the spirit of go. 这应该使您的代码易于理解和显式,并且更本着Go的精神。

The database/sql driver registration is more of a hack and should not be considered best practice. database/sql驱动程序注册更像是黑客,不应被视为最佳实践。

I think you should have one struct for router (which may well be global, like http.DefaultClient) and then in constructor functions for your controllers you'd be able to inject this router as a dependency so that a relevant route is injected for the router. 我认为您应该为路由器提供一个结构(它可能是全局的,例如http.DefaultClient),然后在控制器的构造函数中,您可以将此路由器作为依赖项注入,以便为路由器。 DI+interfaces make your code nice and testable, not only in Go. DI +接口不仅在Go中使您的代码漂亮且可测试。

Just an idea. 只是一个主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM