看了stackoverflow上的问题和其他网站的文章,还是无法解决问题。
这是我的代码:
package routing
import (
"net/http"
"bitbucket.org/codictive/ise/components/user"
)
// Route defines a component route structure.
type Route struct {
Path string
Name string
Method string
Description string
Handler func(w http.ResponseWriter, r *http.Request, data TemplateData)
}
// TemplateData defines data structure which passed to component handlers and rendered to client.
type TemplateData struct {
AppDomain string
Data map[string]interface{}
RequestPath string
Route Route
User *user.User
}
处理程序中使用模板包的Render 函数将 html 模板呈现给客户端浏览器:
package template
import (
"html/template"
"net/http"
"path"
"bitbucket.org/codictive/ise/components/log"
"bitbucket.org/codictive/ise/core/component/routing"
)
// Render executes given template to user's client with given data.
func Render(fp string, data routing.TemplateData, w http.ResponseWriter) {
files := []string{
"storage/templates/master.html",
path.Join("storage/templates", fp),
}
tmpl, err := template.New("master.html").Funcs(funcs).ParseFiles(files...)
if err != nil {
log.Error("[Render] Template creation failed. (%v)", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, data); err != nil {
log.Error("[Render] Template execution failed. (%v)", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
每个组件都依赖于路由包来定义它的路由:
// Component defines application component structure.
type Component struct {
Name string
Config interface{}
Routes []routing.Route
// Boot filters
Before func()
After func()
}
组件处理程序也使用routing.TemplateData:
// indexHandler displays application homepage.
func indexHandler(w http.ResponseWriter, r *http.Request, data routing.TemplateData) {
}
所以代码高度依赖于 routing.TemplateData 这是我的问题;因为TemplateData还依赖于routing.Route和user.User:
我无法为 TemplateData 制作另一个包;它只是将导入周期移到那里。
另外我认为我不能使用接口(interface),因为循环针对的是类型而不是函数。
我无法将所有这些都放在一个包中。
我不想创建单一用途的包(例如 user/models、user/handlers ...)只是为了绕过循环,因为可能。
如何解决导入周期问题?
最佳答案
这里的结构存在一些问题,因此您需要进行一些更改。一些一般准则:
所以看看你的问题:
您的组件目前知道路由,但不需要 - 它们应该公开处理程序,您可以让应用程序或主包连接处理程序和路由器。处理程序不应该知道它们是如何使用的。
您的路由器知道模板和渲染,但不需要,从那里删除 TemplateData,处理程序应该通过导入您的模板包并使用它来渲染自己。
您的 TemplateData 知道用户但不必知道 - 我会删除它并将渲染上下文减少到 Data map[string]interface{},因为用户可以添加到那里并且将它分开不会'添加不多但确实意味着您的模板包必须了解您的特定用户类型,这很糟糕。
前三点是去除不应该存在的依赖的问题——你的包太相互依赖了。
所以以开放的心态列出可能的布局解决方案(最好的取决于项目的结构和复杂性):
您已经在某种程度上按资源进行拆分(您称之为组件),所以让我们开始吧。这是一个示例布局(每个条目都是一个包):
你说我不想创建单一用途的包,你可能觉得这违反了,但我建议你试试看,我认为它最接近你建议的结构。
这将关于用户的一切都放在一个地方,让页面处理程序根据需要拉入用户或其他资源,而不会用关于用户的信息污染页面说 - 它迫使你将组件完全分开,除了在处理程序中,允许拉入通常需要的多个组件。您可以找到此类结构的示例 here .这意味着只有应用程序和处理程序知道其他包,每个其他包都可以完全独立(因此循环依赖性没有变化)。
好消息是,一旦你解决了这些问题,你会发现你的包更加独立,这个约束(强加以加快编译时间)是我最喜欢的 Go 部分之一,因为它也迫使你拥有相当解耦的设计。
关于go - 类型导入周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46388701/
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否
我正在尝试创建一个与compass一起使用的本地配置文件,这样我们就可以处理开发人员机器上的不同导入路径。到目前为止,我已经尝试将文件导入到异常block中,以防它不存在,然后进一步使用该变量:local_config.rbVENV_FOLDER='venv'config.rbVENV_FOLDER='.'beginrequire'local_config.rb'rescueLoadErrorendputsVENV_FOLDER通常我是一名Python开发人员,所以我希望导入将VENV_FOLDER的值更改为venv,但它仍然是。之后。有没有一种方法可以导入local_config.r
我想使用PostgreSQL中的point类型。我已经完成了:railsgmodelTestpoint:point最终的迁移是:classCreateTests当我运行时:rakedb:migrate结果是:==CreateTests:migrating====================================================--create_table(:tests)rakeaborted!Anerrorhasoccurred,thisandalllatermigrationscanceled:undefinedmethod`point'for#/hom
希望我没有误解“ducktyping”的含义,但从我读到的内容来看,这意味着我应该根据对象如何响应方法而不是它是什么类型/类来编写代码。代码如下:defconvert_hash(hash)ifhash.keys.all?{|k|k.is_a?(Integer)}returnhashelsifhash.keys.all?{|k|k.is_a?(Property)}new_hash={}hash.each_pair{|k,v|new_hash[k.id]=v}returnnew_hashelseraise"CustomattributekeysshouldbeID'sorPropertyo
我试图像这样在我的测试用例中执行获取:request.env['CONTENT_TYPE']='application/json'get:index,:application_name=>"Heka"虽然,它失败了:ActionView::MissingTemplate:Missingtemplatealarm_events/indexwith{:handlers=>[:builder,:haml,:erb,:rjs,:rhtml,:rxml],:locale=>[:en,:en],:formats=>[:html]尽管在我的Controller中我有:respond_to:html,