gpt4 book ai didi

Ruby 嵌套模块作为命名空间

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

我有一个嵌套的模块结构,仅用于命名空间;没有混入类等所以我有这样的代码:

module Lib

module A
def A.foo
puts 'Lib::A::foo'
end
end

module B
def B.bar
puts 'Lib::B::bar'
end
end

end

现在假设我想在模块 A 中再添加一个辅助方法,我希望它可以被两个模块轻松使用。我得到以下信息:
module Lib

module A
def A.foo
puts 'Lib::A::foo'
end
def A.helper
puts 'Lib::A::helper'
end
end

module B
def B.bar
puts 'Lib::B::bar'
A::helper
end
end

end

它似乎有效,但它有一些我想摆脱的缺点:
我不想打电话 helper始终通过其完整的限定名称 ( A::helper ) 从内部 B .我更愿意以某种方式告诉 Ruby 这个命名空间前缀是“默认的”,并简单地将它称为 helper .在 C++ 中,我可以只写 using A::helper内部命名空间 B它会解决问题。但是如何在 Ruby 中做到这一点呢?

我尝试添加 include Aextend AB ,但它们都不起作用。它们似乎只在类内部工作,当这些模块混合在一起时,而不是当它们是独立的,仅用于命名空间目的时。

有没有其他方法可以让它按照我想要的方式工作?

还有件事儿:
假设一个不同的场景,我想要 A::helper只能从内部使用 A的方法,因为它只是一些实现函数,我在这里提取了一些被 A里面的很多函数使用的通用代码,但现在我不想让外界看到它,只是为了 A的方法。我该怎么做?

我试过 module_function + 删除 A.所有其他应该隐藏的函数的前缀,但是它们也隐藏在 A 中的其他方法中,因为它们是实例方法,并且模块不能被实例化。那么我怎样才能对外部世界隐藏一个模块方法,并仍然允许它被其他模块方法内部使用呢?

编辑
为什么投反对票?我试图尽可能清楚,我需要的是 默认命名空间 在另一个命名空间内到 完全摆脱长的完全限定名称 (不仅仅是将它们别名为更短的东西),而且我的问题根本不涉及类和对象,只是用于命名空间目的的普通模块。我还能怎么解释?

命名空间机制在 Ruby 中似乎不像在 C++ 之类的语言中那样被本地完全支持,这不是我的错,而且这似乎只是使用模块和类来拥有真正命名空间的某些功能的副作用(它们像鸭子一样嘎嘎叫,它们有鸭嘴,但它们是鸭嘴兽,而不是鸭子,不应该被宣传为 namespace ,而它们显然不是,因为它只会混淆从其他语言来到 Ruby 的人与真正的 namespace ),也不如果其他编程语言中的概念在 Ruby 中不容易实现,那么您显然无法理解其他编程语言的概念(因为我看到您似乎假装我的问题不存在并恢复到您可以在 Ruby 中轻松完成的事情;但这不是我需要的)。

为什么与我的问题相关的唯一答案已被删除?不酷;.

最佳答案

好的,由于与我的问题相关的唯一答案已被删除,我将尝试自己回答我的问题,基于@sawa 已删除的答案(感谢 @sawa 向我暗示正确的方向)。我对其进行了一些修改以更好地满足我的需求并且更加优雅。稍后我将描述为什么最初的@sawa 的答案不是我想要的。好的,所以不用多说,这是我自己对解决方案的尝试:

module Lib

module A
extend self
def foo
puts 'Lib::A::foo'
end
def helper
puts 'Lib::A::helper'
foo
end
end

module B
extend A
def self.bar
puts 'Lib::B::bar'
helper
end
end

end

puts 'Calling Lib::A::foo:'
Lib::A::foo # => Lib::A::foo

puts 'Calling Lib::A::helper:'
Lib::A::helper # => Lib::A::helper; Lib::A::foo

puts 'Calling Lib::B::bar:'
Lib::B::bar # => Lib::B::bar; Lib::A::helper; Lib::A::foo

这是它的工作原理:
首先,它将所有方法定义为特定模块类本身的实例方法(在本例中为 A)。但是,为了让它们在不实例化的情况下可供外部使用(这对于模块来说毕竟是不可能的),我 extend A模块与自身,这使得这些方法也成为它的类方法。但多亏了它们也是模块 A 的实例方法这一事实。 ,它们可以从该模块的其他方法内部调用,而无需为它们加上模块名称的前缀。模块 B 也是如此,这也 extend s 本身与模块 A的方法,使它们成为他自己的。然后我可以在里面调用他们 B的方法也没有前缀,就像我想要的那样。

如您所见,我不仅可以从外部调用两个模块的方法,就好像它们是它们的类的方法一样,而且我可以调用 A::helper来自 B::foo没有完全限定其名称,但我也可以调用 A::foo来自 A::helper没有资格。这正是我所需要的,并且似乎按我的预期工作。

这种方法的唯一问题可能是它们的接口(interface)混合在一起。这里面的问题不大 B ,因为这正是我真正想要的:能够访问 A的方法好像是 B的方法,而无需为它们加上完整的限定前缀。所以我得到了我应得的。但这可能会导致外部问题,因为它是 B的一个实现细节。它使用 A的方法内部。它不应该泄漏到外部世界,但确实如此。我会尝试通过访问控制以某种方式修复它,也许以某种方式可能。

编辑:是的,可以通过在 extend A 后面插入以下行来完成在 B :
private_class_method *A.public_instance_methods

这样 B可调用 A的方法在内部,但它们不能从外部世界访问。

现在原来@sawa 的解决方案有什么问题:

它一直在使用第三个模块来通过它代理接口(interface)。对我来说,这与其说是一个优雅的解决方案,不如说是一个丑陋的 hack,因为它引入了这个额外的模块,这会使这样一个库的用户感到困惑。他们不知道是否应该使用 AC ,以及为什么要使用这种装置。仅仅通过观察它并不清楚它是如何工作的。它需要一些更彻底的分析来弄清楚它真正做了什么以及为什么以这种方式构建它。这不是一个干净的设计。

另一方面,在我的解决方案中,只有两个模块,正如最初设计的那样,对于这个库的用户来说,它们的目的应该很清楚。有这个奇怪的 extend self ,但它似乎仍然是 Ruby 中比到处散布代理模块更常见的习惯用法。

所以感谢你们的尝试。下次尝试不那么傲慢(当你看到有人提出问题时,他并不总是一个菜鸟)并专注于你心爱的一种真正的语言(不要误会我的意思,我喜欢 Ruby 语言,它很酷而且干净,但它也有一些缺点,就像任何语言一样,最好寻求解决它们,而不是埋头苦干并假装根本没有问题,因为这不是该语言的设计目标)。

关于Ruby 嵌套模块作为命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18585623/

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