匿名模块可以服务于啥目的?
Posted
技术标签:
【中文标题】匿名模块可以服务于啥目的?【英文标题】:What purpose can anonymous modules serve?匿名模块可以服务于什么目的? 【发布时间】:2015-11-11 14:26:12 【问题描述】:anonymous modules 在 Ruby 应用程序中有什么用途?这个概念本身很容易掌握,但我无法想象你会使用这样的东西的任何原因。他们解决了什么问题?
【问题讨论】:
此页面列出了匿名模块的使用示例 - intridea.com/blog/2012/2/13/… 这有点深奥,但它是一种即时收集一堆不同方法的方法。 简单的答案是,它们允许您为事物创建短暂的命名空间,链接中的 mixin 示例是我使用它们的唯一用例。跨度> 【参考方案1】:这里有一个更普遍的原则。
Phil Karlton 有句名言:"There are only two hard problems computer science: cache invalidation and naming things." 所以,给事物命名很难。这意味着,如果我们可以侥幸不为事物命名,我们就应该这样做!
或者,如果您从不同的角度来看:如果命名事物很难,那么给事物命名就意味着事物很重要。但有时,我们的程序中有些东西并不重要,因此不值得命名。
这不是 Ruby 模块独有的。您可以就任何匿名概念提出问题,事实上,这个问题确实一直被问到。当 C# 2.0 引入匿名方法时,人们会问为什么要使用没有名称的方法,当 C# 3.0 引入匿名 lambda(和匿名类型)时,人们会问为什么要使用它们。与 Python 的命名函数相比,Python 的匿名函数受到严格限制,Python 社区问为什么人们需要成熟的匿名函数。当然,作为 Ruby 程序员,我们如此习惯于轻量级(块)和完全具体化 (Proc
s) 匿名函数,以至于我们无法理解为什么我们会不想要使用一个。
Java 从 1.1 开始就有匿名类,从 8 开始就有匿名 lambda。基本上,匿名“事物”无处不在,而且非常有用,尤其是对于快速一次性使用。
例如,如果您只想包装一些现有方法,而无需经历 alias_method
的麻烦(您真的不应该再使用它来解决该问题,Module#prepend
现在存在并且是一个更好的解决方案),你可以这样做:
class Array
prepend(Module.new do
def [](*)
puts 'Before-hook'
super.tap puts 'After-hook'
end
end)
end
p [42][0]
# Before-hook
# After-hook
# => 42
【讨论】:
明亮而清晰。既然您已经用一个简单的例子指出了这一点,它似乎应该是显而易见的。【参考方案2】:这是一个特定于 Rails 的答案,一般与匿名模块无关。
简答
能够在覆盖生成的方法时调用super
。
长答案
给定一个创建方法的模块:
module Generator
def generate_method(name)
define_method(name) do
"I am #name"
end
end
end
在类中调用generate_method
会创建一个新的实例方法:
class MyClass
extend Generator
generate_method :foo
end
MyClass.new.method(:foo) #=> #<Method: MyClass#foo>
调用方法按预期工作:
MyClass.new.foo #=> "I am foo"
但你不能轻易改变foo
:
class MyClass
def foo
super.upcase
end
end
MyClass.new.foo #=> no superclass method `foo'
如果我们的生成器使用匿名模块来定义其中的方法:
module Generator
def generate_method(name)
generated_methods.module_eval do
define_method(name) do
"I am #name"
end
end
end
def generated_methods
@generated_methods ||= begin
mod = Module.new
include(mod)
mod
end
end
end
我们得到:
class MyClass
extend Generator
generate_method :foo
end
MyClass.new.method(:foo) #=> #<Method: MyClass(#<Module:0x007fbd29833658>)#foo>
现在更改 foo
可以正常工作:
class MyClass
def foo
super.upcase
end
end
MyClass.new.foo #=> "I AM FOO"
【讨论】:
这似乎是一个相当复杂的用例——让一个类假装它是某个东西的子类。想要这样做的用例是什么? @DaveNewton Rails 生成了很多方法,您经常需要更改默认实现,例如覆盖 getter 或 setter。我认为能够拨打super
会更方便。
@DaveNewton 更新了我的答案,以澄清它是特定于 Rails 的(这并不明显)。这个例子确实令人费解,但 Rails 也是如此;-)以上是关于匿名模块可以服务于啥目的?的主要内容,如果未能解决你的问题,请参考以下文章
请简要描述一下hadoop,spark,mpi三种计算框架的特点以及分别适用于啥样的场景
将整个 Javascript 文件包装在像“(function() ... )()”这样的匿名函数中的目的是啥?