Go:Reflection Catch 22 reflect软件包

Go:Reflection Catch 22 reflect软件包,reflection,go,Reflection,Go,好的。。我已经或正在编写一个名为mao的web框架包 我想在控制器中定义我的路线 在毛泽东时代 type ( Controller struct { Route Route } Route struct { Name, Host, Path, Method string } ) 在进口包装中 控制器/default.go type DefaultController struct { mao.Controller } fu

好的。。我已经或正在编写一个名为mao的web框架包

我想在控制器中定义我的路线

在毛泽东时代

type (
    Controller struct {
        Route Route
    }
    Route struct {
        Name, Host, Path, Method string
    }
)
在进口包装中

控制器/default.go

type DefaultController struct {
    mao.Controller
}
func (this *DefaultController) Index() Response {
    this.Route = mao.Route{"default_index","localhost","/", "GET"}
}
现在,由于我想在控制器内定义我的路由,路由器在实例化时应该读取所有控制器。这就是问题所在


如何将包名传递给路由器,以便路由器能够获取该包中的所有结构和函数?甚至有可能吗?

在Go中,您所要求的是不可能的,因为它无法枚举包/程序中的所有类型

另一种选择是遵循
数据库/sql
包的指导,并拥有一个系统,其他包可以在导入时向其注册

例如,要在该软件包中使用PostgreSQL驱动程序,可以执行以下操作:

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

...
db, err := sql.Open("postgres", "dbname=test")
postgres驱动程序是在初始化
github.com/lib/pq
包的过程中注册的。以下是该软件包中的相关代码(排除一些不相关的部分):


也许您可以创建这样的注册API来查找程序中可用的各种实现?

老实说,我认为您这样做是错误的。 “自动注册”混淆了所发生的事情,并将导致难以测试和推理的代码

我建议让控制器成为一个具体控制器应该满足的接口 并且在路由器上有一个方法
Add(c Controller)
,在主叫项目中分配控制器 (导入路由器和控制器)。这将使您的代码易于理解和明确 更符合围棋的精神


数据库/sql
驱动程序注册更像是一种黑客行为,不应被视为最佳实践。

我认为您应该为路由器提供一个结构(可能是全局的,如http.DefaultClient)然后,在控制器的构造函数中,您可以将此路由器作为依赖项注入,以便为路由器注入相关路由。DI+接口使您的代码美观且可测试,而不仅仅是在Go中


只是个主意

我认为这是重复:(答案是“不,不可能”)我不太确定这是不可能的。我偶然发现了另一种方法,可能是为每个控制器提供一个Reflect()方法,还有一种方法是在控制器内没有路由,并使用controller Reflect.Type作为路由属性。我不喜欢“这是不可能的”一切都是可能的,这只是一个是否值得权衡的问题。我想我会问一下果仁。谢谢你提到另一个问题tho。我的意思是,仅仅用软件包是不可能得到所有函数和结构的。显然,您可以实现一个包含所有函数的reflect.Type的包级切片,或者获取一个解析器并解析源文件,但是“不可能”的意思是,从包中获取信息是不可能的,因为信息没有保留在编译中。@Jsor您说得对。我从新开始,在预先定义路由的地方采用了不同的方法。我现在有了一些不同的东西
类型Route struct{Method string Path string Controller interface{}regex*regexp.regexp mu sync.RWMutex}
,然后反映出接口的类型或“ValueOf”{它是这样的,然后将正则表达式匹配的结果作为参数调用该方法,非常简单(而且高效),但必须对其进行扩展。这与webgo.io的功能类似,因为您可以拥有一个函数并将其传递给params和任何返回类型,并且根据返回类型使用不同的响应请求的方式。
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{})
}