为什么不用ruby支持方法重载?
而不是支持方法重载Ruby覆盖现有的方法。 任何人都可以解释为什么语言是这样devise的?
方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。 这些不同的签名可以是,
- 具有不同数据types的参数,例如:
method(int a, int b) vs method(String a, String b)
- 可变数量的参数,例如:
method(a) vs method(a, b)
我们不能用第一种方法实现方法重载,因为在ruby( dynamictypes语言 )中没有数据types声明。 所以定义上述方法的唯一方法是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.
所以ruby需要在方法查找链中维护一个具有唯一名称的方法。
“重载”这个术语在Ruby中根本就没有意义。 它基本上是“基于静态参数的调度”的同义词,但是Ruby根本没有静态调度。 所以,Ruby不支持基于参数的静态分派,是因为它不支持静态分派,句点。 它不支持任何types的静态调度,不论是基于参数还是其他。
现在,如果你实际上没有具体询问重载,但也许是关于基于dynamic参数的调度,那么答案是:因为Matz没有实现它。 因为没有人打扰提出。 因为没有人打扰执行它。
一般来说,使用可选参数和可变长度参数列表的语言进行基于dynamic参数的调度是非常困难的, 更难以理解。 即使在使用基于静态参数的调度和没有可选参数(例如Java)的语言中,有时也几乎不可能告诉一个凡人, 哪个超载将被选中。
在C#中,实际上可以将任何 3-SAT问题编码为重载parsing,这意味着C#中的重载parsing是NP-hard。
现在用dynamic调度来尝试一下,你有额外的时间维度在你的脑海。
有些语言是基于一个过程的所有参数dynamic调度的,而不是面向对象的语言,它们只是在“隐藏”的第零self
参数上进行调度。 例如,Common Lisp会派发所有参数的dynamictypes,甚至是dynamic值。 Clojure在所有参数的任意函数上发送(这个BTW非常酷,非常强大)。
但是我不知道任何使用dynamic参数派发的OO语言。 马丁·奥德斯基(Martin Odersky)表示,他可能会考虑向Scala添加基于参数的调度,但前提是他可以同时删除重载, 并且与现有的使用重载并与Java兼容的Scala代码向后兼容(他特别提到了Swing和AWT其中扮演了一些非常复杂的技巧,几乎讨论Java的相当复杂的重载规则的每一个讨厌的黑暗angular落案例)。 我已经有了一些关于向Ruby添加基于参数的调度的想法,但是我永远不可能知道如何以向后兼容的方式来做到这一点。
我认为你正在寻找这样做的能力:
def my_method(arg1) .. end def my_method(arg1, arg2) .. end
Ruby以不同的方式支持这一点:
def my_method(*args) if args.length == 1 #method 1 else #method 2 end end
一个常见的模式也是作为一个散列传递选项:
def my_method(options) if options[:arg1] and options[:arg2] #method 2 elsif options[:arg1] #method 1 end end my_method arg1: 'hello', arg2: 'world'
希望有所帮助
方法重载在静态types的语言中是有意义的,在这里你可以区分不同types的参数
f(1) f('foo') f(true)
以及不同数量的论据之间
f(1) f(1, 'foo') f(1, 'foo', true)
ruby中不存在第一个区别。 Ruby使用dynamictypes或“鸭子打字”。 第二个区别可以通过默认参数或通过使用参数来处理:
def f(n, s = 'foo', flux_compensator = true) ... end def f(*args) case args.size when ... when 2 ... when 3 ... end end
这并不回答为什么ruby没有方法重载,但第三方库可以提供它的问题。
contracts.ruby库允许超载。 从教程改编的例子:
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
请注意,这实际上比Java的重载更强大,因为您可以指定要匹配的值(例如1
),而不仅仅是types。
你会看到使用这个虽然减less的性能; 你将不得不运行基准来决定你能容忍多less。
我经常做以下的结构:
def method(param) case param when String method_for_String(param) when Type1 method_for_Type1(param) ... else #default implementation end end
这允许对象的用户使用干净清晰的method_name:方法但是如果他想优化执行,他可以直接调用正确的方法。
此外,它使你的考试清晰和更好。