【问题标题】:Go: Reflection catch22 reflect package去:反射catch22反射包
【发布时间】:2014-03-07 04:19:07
【问题描述】:

好的.. 我有,或者正在编写一个名为 mao 的 web 框架包。

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

在毛

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

在mao导入包中

控制器/default.go

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

现在我想在控制器中定义我的路由,路由器在实例化时应该读取所​​有控制器。这就是问题所在。

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

【问题讨论】:

  • 我认为这是重复的:stackoverflow.com/questions/20803758/…(答案是“不,不可能”)
  • 我不太确定这不可能。我偶然发现godoc.org/code.google.com/p/go.tools/go/types 另一种方法可能是给每个控制器一个 Reflect() 方法,另一种方法是在控制器内部没有路由并使用 Controller reflect.Type 作为 Route 属性。我不喜欢“不可能”,一切皆有可能,这只是是否值得权衡的问题。我想我会用golang-nuts问。感谢您参考其他问题。
  • 我的意思是仅仅使用包是不可能获得所有函数和结构的。显然,你可以,比如说,实现一个包含所有函数的 reflect.Type 的包级切片,或者去获取一个解析器并解析源文件,但从从包中获取信息的意义上,这是“不可能的”。不可能,因为编译中没有保留信息。
  • @Jsor 你是对的。我重新开始并采取了不同的方法,预先定义了路线。

标签: reflection go


【解决方案1】:

你所问的在 Go 中是不可能的,因为它没有办法枚举包/程序中的所有类型。

另一种选择是效仿database/sql 包,并拥有一个系统,其他包可以在导入时注册。

例如,要在该软件包中使用 PostgreSQL 驱动程序,您可以这样做:

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

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

postgres 驱动程序在 github.com/lib/pq 包的初始化期间注册。以下是该包中的相关代码(省略了一些不相关的部分):

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{})
}

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

【讨论】:

    【解决方案2】:

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

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

    database/sql 驱动程序注册更像是一种 hack,不应被视为最佳实践。

    【讨论】:

    • 我现在有一些不同的东西type Route struct { Method string Path string Controller interface{} regex *regexp.Regexp mu sync.RWMutex } 然后反映它是什么类型或“ValueOf”接口{},然后使用正则表达式匹配的结果作为参数调用该方法,如此简单(和高效),但必须扩展它。它类似于 webgo.io 所做的,因为您可以拥有一个函数并将其传递参数并具有任何返回类型,并且根据返回类型使用不同的方式来响应请求。
    【解决方案3】:

    我认为你应该有一个路由器结构(很可能是全局的,比如 http.DefaultClient),然后在你的控制器的构造函数中,你可以将该路由器作为依赖项注入,以便相关路由是为路由器注入。 DI+接口让你的代码变得漂亮且可测试,不仅在 Go 中。

    只是一个想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-23
      • 1970-01-01
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 2011-06-18
      • 2010-09-21
      • 2014-11-04
      相关资源
      最近更新 更多