为什么 ruby 不支持方法重载?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9373104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't ruby support method overloading?
提问by Rambo
Instead of supporting method overloading Ruby overwrites existing methods. Can anyone explain why the language was designed this way?
Ruby 不支持方法重载,而是覆盖现有方法。谁能解释为什么这种语言是这样设计的?
回答by J?rg W Mittag
"Overloading" is a term that simply doesn't even make sense in Ruby. It is basically a synonym for "static argument-based dispatch", but Ruby doesn't havestatic dispatch at all. So, the reason why Ruby doesn't support static dispatch based on the arguments, is because it doesn't support static dispatch, period. It doesn't support static dispatch of any kind, whether argument-based or otherwise.
“重载”是一个在 Ruby 中根本没有意义的术语。它基本上是“静态的基于论证的调度”的代名词,但红宝石不具备静态调度可言。所以,Ruby 之所以不支持基于参数的静态调度,是因为它不支持静态调度,周期。它不支持任何类型的静态调度,无论是基于参数的还是其他方式。
Now, if you are notactually specifically asking about overloading, but maybe about dynamicargument-based dispatch, then the answer is: because Matz didn't implement it. Because nobody else bothered to propose it. Because nobody else bothered to implement it.
现在,如果你是不是真正专门询问有关超载的,而是关于动态基于论证的调度,那么答案是:因为马茨并未实现它。因为没有其他人费心提出它。因为没有其他人费心去实施它。
In general, dynamic argument-based dispatch in a language with optional arguments and variable-length argument lists, is veryhard to get right, and even harderto keep it understandable. Even in languages with staticargument-based dispatch and without optional arguments (like Java, for example), it is sometimes almost impossible to tell for a mere mortal, whichoverload is going to be picked.
在与可选参数和可变长度参数列表中选择语言一般情况下,基于动态参数的分派,是非常难以得到正确的,甚至更难保持它可以理解的。即使在具有基于静态参数的调度且没有可选参数的语言中(例如 Java),有时也几乎不可能告诉一个凡人,将选择哪个重载。
In C#, you can actually encode any3-SAT problem into overload resolution, which means that overload resolution in C# is NP-hard.
在 C# 中,您实际上可以将任何3-SAT 问题编码为重载解析,这意味着 C# 中的重载解析是 NP-hard 的。
Now try that with dynamicdispatch, where you have the additional time dimension to keep in your head.
现在尝试使用动态调度,在那里你有额外的时间维度来记住。
There are languages which dynamically dispatch based on all arguments of a procedure, as opposed to object-oriented languages, which only dispatch on the "hidden" zeroth selfargument. Common Lisp, for example, dispatches on the dynamic types and even the dynamic values of all arguments. Clojure dispatches on an arbitrary function of all arguments (which BTW is extremely cool and extremely powerful).
有一些语言基于过程的所有参数动态调度,与面向对象的语言相反,后者只调度“隐藏的”第零个self参数。例如,Common Lisp 调度动态类型,甚至所有参数的动态值。Clojure 调度所有参数的任意函数(顺便说一句,它非常酷且非常强大)。
But I don't know of any OO language with dynamic argument-based dispatch. Martin Odersky said that he mightconsider adding argument-based dispatch to Scala, but onlyif he can remove overloading at the same time andbe backwards-compatible both with existing Scala code that uses overloading and compatible with Java (he especially mentioned Swing and AWT which play some extremely complex tricks exercising pretty much every nasty dark corner case of Java's rather complex overloading rules). I've had some ideas myself about adding argument-based dispatch to Ruby, but I never could figure out how to do it in a backwards-compatible manner.
但我不知道任何具有基于动态参数的调度的 OO 语言。马丁·奥德斯基说,他可能会考虑增加基于论证的派遣斯卡拉,但只有当他可以删除在同一时间超载和向后兼容都与现有的Scala代码,使用重载和与Java兼容(他特别提到Swing和AWT它发挥了一些极其复杂的技巧,几乎可以锻炼 Java 相当复杂的重载规则的每一个令人讨厌的黑暗角落情况)。我自己有一些关于向 Ruby 添加基于参数的调度的想法,但我从来不知道如何以向后兼容的方式来做到这一点。
回答by nkm
Method overloading can be achieved by declaring two methods with the same name and different signatures. These different signatures can be either,
方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。这些不同的签名可以是,
- Arguments with different data types, eg:
method(int a, int b) vs method(String a, String b) - Variable number of arguments, eg:
method(a) vs method(a, b)
- 具有不同数据类型的参数,例如:
method(int a, int b) vs method(String a, String b) - 可变数量的参数,例如:
method(a) vs method(a, b)
We cannot achieve method overloading using the first way because there is no data type declaration in ruby(dynamic typed language). So the only way to define the above method is def(a,b)
我们无法使用第一种方式实现方法重载,因为 ruby(动态类型语言)中没有数据类型声明。所以定义上述方法的唯一方法是def(a,b)
With the second option, it might look like we can achieve method overloading, but we can't. Let say I have two methods with different number of arguments,
使用第二个选项,看起来我们可以实现方法重载,但我们不能。假设我有两个参数数量不同的方法,
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.
So ruby needs to maintain one method in the method look up chain with a unique name.
所以 ruby 需要在方法查找链中维护一个具有唯一名称的方法。
回答by Derek Ekins
I presume you are looking for the ability to do this:
我想您正在寻找执行此操作的能力:
def my_method(arg1)
..
end
def my_method(arg1, arg2)
..
end
Ruby supports this in a different way:
Ruby 以不同的方式支持这一点:
def my_method(*args)
if args.length == 1
#method 1
else
#method 2
end
end
A common pattern is also to pass in options as a hash:
一个常见的模式也是将选项作为散列传递:
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'
Hope that helps
希望有帮助
回答by bjelli
Method overloading makes sense in a language with static typing, where you can distinguish between different types of arguments
方法重载在具有静态类型的语言中很有意义,您可以在其中区分不同类型的参数
f(1)
f('foo')
f(true)
as well as between different number of arguments
以及不同数量的参数之间
f(1)
f(1, 'foo')
f(1, 'foo', true)
The first distinction does not exist in ruby. Ruby uses dynamic typing or "duck typing". The second distinction can be handled by default arguments or by working with arguments:
第一个区别在 ruby 中不存在。Ruby 使用动态类型或“鸭子类型”。第二个区别可以通过默认参数或通过使用参数来处理:
def f(n, s = 'foo', flux_compensator = true)
...
end
def f(*args)
case args.size
when
...
when 2
...
when 3
...
end
end
回答by Kelvin
This doesn't answer the question of why ruby doesn't have method overloading, but third-party libraries can provide it.
这并没有回答为什么 ruby 没有方法重载的问题,但第三方库可以提供它。
The contracts.rubylibrary allows overloading. Example adapted from the tutorial:
该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
Note that this is actually more powerful than Java's overloading, because you can specify values to match (e.g. 1), not merely types.
请注意,这实际上比 Java 的重载更强大,因为您可以指定要匹配的值(例如1),而不仅仅是类型。
You will see decreased performance using this though; you will have to run benchmarks to decide how much you can tolerate.
但是,使用它您会看到性能下降;您将不得不运行基准测试来决定您可以容忍多少。
回答by Oshan Wisumperuma
there are already great answers on why side of the question. however, if anyone looking for other solutions checkout functional-rubygem which is inspired by Elixir pattern matchingfeatures.
关于问题的原因已经有很好的答案。但是,如果有人正在寻找其他解决方案,请查看受 Elixir模式匹配功能启发的功能性 rubygem 。
class Foo
include Functional::PatternMatching
## Constructor Over loading
defn(:initialize) { @name = 'baz' }
defn(:initialize, _) {|name| @name = name.to_s }
## Method Overloading
defn(:greet, :male) {
puts "Hello, sir!"
}
defn(:greet, :female) {
puts "Hello, ma'am!"
}
end
foo = Foo.new or Foo.new('Bar')
foo.greet(:male) => "Hello, sir!"
foo.greet(:female) => "Hello, ma'am!"
回答by Dam
I often do the following structure :
我经常做以下结构:
def method(param)
case param
when String
method_for_String(param)
when Type1
method_for_Type1(param)
...
else
#default implementation
end
end
This allow the user of the object to use the clean and clear method_name : method But if he want to optimise execution, he can directly call the correct method.
这允许对象的用户使用干净清晰的 method_name : method 但是如果他想优化执行,他可以直接调用正确的方法。
Also, it makes your test clearers and betters.
此外,它使您的测试更清晰和更好。

