gpt4 book ai didi

ruby:如何正确要求(避免循环依赖)

转载 作者:数据小太阳 更新时间:2023-10-29 06:38:02 24 4
gpt4 key购买 nike

今天我遇到了一个奇怪的问题:在模块上出现“缺少方法”错误,但方法在那里,并且需要定义模块的文件。经过一些搜索后,我发现了一个循环依赖,其中 2 个文件相互依赖,现在我假设 ruby​​ 默默地中止了循环需求。


编辑开始:示例

文件 'a.rb':

require './b.rb'

module A
def self.do_something
puts 'doing..'
end
end

文件 'b.rb':

require './a.rb'

module B
def self.calling
::A.do_something
end
end

B.calling

执行 b.rb 给出 b.rb:5:in 'calling': uninitialized constant A (NameError)。这两个文件都必须有要求,因为它们打算从命令行独立运行(我省略了该代码以使其简短)。所以 B.calling 必须在那里。一种可能的解决方案是将要求包装在 if __FILE__ == $0 中,但这似乎不是正确的方法。

编辑结束


为了避免这些难以发现的错误(顺便说一句,如果 require 抛出异常不是更好吗?),是否有一些关于如何构建项目以及在哪里需要什么的指南/规则?例如,如果我有

module MainModule
module SubModule
module SubSubModule
end
end
end

我应该在哪里需要子模块?全部在主中,还是只有主中的子和子中的子子?

任何帮助都会非常好。

总结

forforfs 的回答和评论中讨论了为什么会发生这种情况。

到目前为止,最佳实践(正如 lain 指出或暗示的那样)似乎如下(如果我错了请纠正我):

  1. 将顶级命名空间中的每个模块或类放在一个以模块/类命名的文件中。在我的示例中,这将是 1 个名为“main_module.rb”的文件。如果有子模块或子类,创建一个以模块/类命名的目录(在我的例子中是一个目录'main_module',并将子类/子模块的文件放在那里(在例子1中名为'sub_module.rb'的文件) . 对命名空间的每个级别重复此操作。
  2. 需要逐步(在示例中,MainModule 需要 SubModule,而 Submodule 需要 子子模块)
  3. 将“运行”代码与“定义”代码分开。在运行代码中需要一次你的顶级模块/类,所以由于 2. 你所有的库功能现在应该可用,并且你可以运行任何定义的方法。

感谢所有回答/评论的人,这对我帮助很大!

最佳答案

不久前在 Ruby 邮件列表上询问了这个问题后,当我曾经在我的库中有一个文件只是为了需要东西时,我改变了这两个规则:

  1. 如果一个文件需要来自同一库中另一个文件的代码,我会在需要代码的文件中使用 require_relative

  2. 如果文件需要来自不同库的代码,我会在需要代码的文件中使用 require

据我所知,Ruby 按照要求的顺序要求,因此循环依赖无关紧要。

( ruby v1.9.2)

在回答有关显示循环依赖问题的示例的评论时:

实际上,该示例的问题不在于要求是循环的,而是在要求完成之前调用了 B.calling。如果您从 b.rb 中删除 B.calling,它就可以正常工作。例如,在 irb 中没有在代码文件中调用 B.calling 但之后运行:

$ irb
require '/Volumes/RubyProjects/Test/stackoverflow8057625/b.rb'
=> true
B.calling
doing..
=> nil

关于ruby:如何正确要求(避免循环依赖),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8057625/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com