方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。这些不同的签名可以是, 1.具有不同数据类型的参数,例如:第一个月 1.参数数量可变,例如:method(a) vs method(a, b) 我们不能用第一种方法实现方法重载,因为在ruby(动态类型语言)中没有数据类型声明,所以定义上述方法的唯一方法是def(a,b) 对于第二种选择,看起来我们可以实现方法重载,但实际上我们不能。假设我有两个参数数量不同的方法,
def method(a); end;
def method(a, b = true); end; # second argument has a default value
method(10)
# Now the method call can match the first one as well as the second one,
# so here is the problem.
class Factorial
include Contracts
Contract 1 => 1
def fact(x)
x
end
Contract Num => Num
def fact(x)
x * fact(x - 1)
end
end
# try it out
Factorial.new.fact(5) # => 120
9条答案
按热度按时间k7fdbhmy1#
“重载”这个术语在Ruby中根本没有意义。它基本上是“基于参数的静态调度”的同义词,但是Ruby根本没有静态调度。所以,Ruby不支持基于参数的静态调度的原因是因为它不支持静态调度,句号。它不支持任何类型的静态调度,不管是基于参数的还是其他类型的。
现在,如果您实际上“不是”专门询问重载,而是"动态“基于参数的调度,那么答案是:因为马茨没有实现它。因为没有人费心去提出它。因为没有人费心去实现它。
一般来说,在一种带有可选参数和可变长度参数列表的语言中,基于参数的动态调度是非常难以正确理解的,甚至更难以让人理解。即使在带有基于参数的静态调度而没有可选参数的语言中(例如Java),有时候对于一个凡人来说,要分辨出将要选择哪个重载几乎是不可能的。
在C#中,实际上可以将 * 任何 * 3-SAT问题编码为重载解析,这意味着C#中的重载解析是NP难的。
现在,尝试一下 dynamic dispatch,在这里,您需要在头脑中记住额外的时间维度。
有些语言基于过程的所有参数进行动态调度,而面向对象语言只在“隐藏的”第零个
self
参数上进行调度。例如,Common Lisp在所有参数的动态类型甚至动态值上进行调度。Clojure在所有参数的任意函数上进行调度(顺便说一句,这非常酷,也非常强大)。但是我不知道有哪种OO语言支持动态的基于参数的分派,MartinOdersky说他 * 可能 * 会考虑在Scala中添加基于参数的分派。但是 * 只有 * 他能够同时移除重载 * 并且 * 与使用重载的现有Scala代码向后兼容并且与Java兼容(他特别提到了Swing和AWT,它们使用了一些极其复杂的技巧,几乎运用了Java相当复杂的重载规则的每一个令人讨厌的黑暗角落)。关于向Ruby添加基于参数的分派,我自己也有一些想法,但我从来没有弄清楚如何以向后兼容的方式来实现。
rpppsulh2#
方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。这些不同的签名可以是,
1.具有不同数据类型的参数,例如:第一个月
1.参数数量可变,例如:
method(a) vs method(a, b)
我们不能用第一种方法实现方法重载,因为在ruby(动态类型语言)中没有数据类型声明,所以定义上述方法的唯一方法是
def(a,b)
对于第二种选择,看起来我们可以实现方法重载,但实际上我们不能。假设我有两个参数数量不同的方法,
所以ruby需要在方法查找链中维护一个具有唯一名称的方法。
trnvg8h33#
我猜你正在寻找这样做的能力:
Ruby以不同的方式支持这一点:
一种常见的模式是将选项作为哈希值传入:
fnatzsnv4#
方法重载在使用静态类型的语言中是有意义的,在这种语言中可以区分不同类型的参数
以及在不同数量的参数之间
第一个区别在Ruby中并不存在,Ruby使用动态类型或“鸭子类型”。第二个区别可以通过默认参数或使用参数来处理:
7fyelxc55#
这并没有回答为什么ruby没有方法重载,但是第三方库可以提供方法重载。
contracts.ruby库允许重载。示例改编自教程:
注意,这实际上比Java的重载更强大,因为您可以指定要匹配的值(例如
1
),而不仅仅是类型。但是,您会发现使用此方法会降低性能;您必须运行基准来确定您可以容忍的程度。
cedebl8k6#
我经常做以下结构:
这允许对象的用户使用clean和clear method_name:但是如果他想优化执行,他可以直接调用正确的方法。
此外,它使您的测试更清晰和更好。
vatpfxk57#
关于为什么的问题已经有了很好的答案。但是,如果有人想要其他的解决方案,请 checkout functional-ruby Gem,它的灵感来自于Elixir pattern matching的特性。
fcwjkofz8#
我偶然看到了Ruby的创始人松本幸弘(Yukihiro松本,又名“Matz”)的精彩访谈。顺便说一句,他在访谈中解释了自己的推理和意图。这是对@nkm对这个问题的出色例证的一个很好的补充。我已经强调了回答你关于Ruby为什么要这样设计的问题的部分:
正交与和谐
比尔·文纳斯:Dave托马斯还声称**如果我让你添加一个正交的特征,你不会这么做。**你想要的是和谐的东西。这是什么意思?
松本幸弘:我相信一致性和正交性是设计的工具,而不是设计的主要目标。
比尔·文纳斯:正交性在本文中的含义是什么?
松本幸弘:正交性的一个例子是允许小特性或语法的任意组合。例如,C++既支持函数的默认参数值,也支持基于参数的函数名重载。这两种特性在语言中都是很好的特性,但是因为它们是正交的,所以可以同时应用这两种特性。编译器知道如何同时应用这两种特性。如果不明确,编译器会标记一个错误。但是如果我看代码,我也需要用我的大脑来应用这个规则。我需要猜测编译器是如何工作的。如果我是对的,我足够聪明,那就没有问题。但是如果我不够聪明,我真的不够聪明,它会引起混淆。结果对于普通人来说将是意想不到的。这是正交性如何糟糕的一个例子。
资料来源:“Ruby的哲学”,与松本幸弘的对话,第一部分,比尔·文纳斯,2003年9月29日,网址:https://www.artima.com/intv/ruby.html
hof1towb9#
静态类型语言支持方法重载,这涉及到它们在编译时的绑定。另一方面,Ruby是一种动态类型语言,根本不支持静态绑定。在具有可选参数和可变长度参数列表的语言中,也很难确定在基于参数的动态调度期间将调用哪个方法。此外,Ruby是用C实现的,其本身不支持方法重载。