是否可以为子模块提供与顶级类相同的名称? [英] Is it possible to give a sub-module the same name as a top-level class?

查看:18
本文介绍了是否可以为子模块提供与顶级类相同的名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:

这就是问题所在,简化为一个最小的例子:

# bar.rb班级酒吧结尾# foo/bar.rb模块 Foo::Bar结尾# foo.rbFoo类包括 Foo::Bar结尾# runner.rb需要酒吧"需要'foo'

<前>➔ 红宝石跑步者.rb./foo.rb:2: 警告: Foo::Bar 引用的顶级常量 Bar./foo.rb:2:in `include': 错误的参数类型类(预期模块)(类型错误)来自 ./foo.rb:2来自 runner.rb:2:in `require'来自 runner.rb:2

解决方案

优秀;您的代码示例非常清晰.你所拥有的是一个花园式的循环依赖,被 Ruby 的范围解析运算符的特性所掩盖.

当你运行 Ruby 代码 require 'foo' 时,ruby 会找到 foo.rb 并执行它,然后找到 foo/bar.rb代码> 并执行它.因此,当 Ruby 遇到您的 Foo 类并执行 include Foo::Bar 时,它会在 Foo 类中查找名为 Bar 的常量,因为这就是 Foo::Bar 表示的.当它找不到一个时,它会在其他封闭范围内搜索名为 Bar 的常量,并最终在顶层找到它.但是that Bar 是一个类,所以不能被included.

即使你可以说服requirefoo.rb之前运行foo/bar.rb,也无济于事;module Foo::Bar 的意思是找到常量Foo,如果它是一个类或一个模块,开始在其中定义一个名为Bar的模块".Foo 还没有被创建,所以 require 仍然会失败.

Foo::Bar 重命名为 Foo::UserBar 也无济于事,因为名称冲突最终不是问题.

那么你做什么?在高层次上,您必须以某种方式打破循环.最简单的是将 Foo 定义为两部分,如下所示:

# bar.rb班级酒吧A = 4结尾# foo.rbFoo类# 不依赖于 Foo::Bar 的东西放在这里.结尾# foo/bar.rb模块 Foo::BarA = 5结尾class Foo # 是的,我们在 foo/bar.rb 中重新打开类 Fooinclude Bar # 请注意,您不需要 Foo:: 因为我们会首先自动搜索 Foo.结尾酒吧::A # =>4Foo::Bar::A # =>5

希望这会有所帮助.

Background:

Here's the problem, distilled down to a minimal example:

# bar.rb
class Bar
end

# foo/bar.rb
module Foo::Bar
end

# foo.rb
class Foo
  include Foo::Bar
end

# runner.rb
require 'bar'
require 'foo'

➔ ruby runner.rb
./foo.rb:2: warning: toplevel constant Bar referenced by Foo::Bar
./foo.rb:2:in `include': wrong argument type Class (expected Module) (TypeError)
    from ./foo.rb:2
    from runner.rb:2:in `require'
    from runner.rb:2

解决方案

Excellent; your code sample is very clarifying. What you have there is a garden-variety circular dependency, obscured by the peculiarities of Ruby's scope-resolution operator.

When you run the Ruby code require 'foo', ruby finds foo.rb and executes it, and then finds foo/bar.rb and executes that. So when Ruby encounters your Foo class and executes include Foo::Bar, it looks for a constant named Bar in the class Foo, because that's what Foo::Bar denotes. When it fails to find one, it searches other enclosing scopes for constants named Bar, and eventually finds it at the top level. But that Bar is a class, and so can't be included.

Even if you could persuade require to run foo/bar.rb before foo.rb, it wouldn't help; module Foo::Bar means "find the constant Foo, and if it's a class or a module, start defining a module within it called Bar". Foo won't have been created yet, so the require will still fail.

Renaming Foo::Bar to Foo::UserBar won't help either, since the name clash isn't ultimately at fault.

So what can you do? At a high level, you have to break the cycle somehow. Simplest is to define Foo in two parts, like so:

# bar.rb
class Bar
  A = 4
end

# foo.rb
class Foo
  # Stuff that doesn't depend on Foo::Bar goes here.
end

# foo/bar.rb
module Foo::Bar
  A = 5
end

class Foo # Yep, we re-open class Foo inside foo/bar.rb
  include Bar # Note that you don't need Foo:: as we automatically search Foo first.
end

Bar::A      # => 4
Foo::Bar::A # => 5

Hope this helps.

这篇关于是否可以为子模块提供与顶级类相同的名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆