Answers:
方法重载可以通过声明两个具有相同名称和不同签名的方法来实现。这些不同的签名可以是
method(int a, int b) vs method(String a, String b)
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.
因此,ruby需要在方法查找链中维护一个具有唯一名称的方法。
“重载”是一个在Ruby中甚至根本没有意义的术语。它基本上是“静态的基于论证的调度”的代名词,但红宝石不具备静态调度可言。因此,Ruby不基于参数支持静态分派的原因是因为它不支持period的静态分派。它不支持任何类型的静态分派,无论是基于参数还是其他方式。
现在,如果您不是真正地在问有关重载的问题,而是关于基于参数的动态分派的问题,那么答案是:因为Matz没有实现它。因为没有人愿意提出建议。因为没有人愿意执行它。
在与可选参数和可变长度参数列表中选择语言一般情况下,基于动态参数的分派,是非常难以得到正确的,甚至更难保持它可以理解的。即使在具有基于静态参数的分派且没有可选参数的语言中(例如Java),有时也几乎不可能只说出凡人,而是会选择哪个重载。
在C#中,您实际上可以将任何 3-SAT问题编码为重载分辨率,这意味着C#中的重载分辨率是NP-hard。
现在尝试使用动态调度,在该调度中您将拥有更多的时间维度。
有一些语言可以根据过程的所有参数动态地进行分派,而与面向对象的语言相反,它们仅在“隐藏的”第零个self
参数上进行分派。例如,Common Lisp调度动态类型,甚至所有参数的动态值。Clojure调度所有参数的任意函数(BTW非常酷,而且功能非常强大)。
但是我不知道任何基于动态参数调度的OO语言。马丁·奥德斯基说,他可能会考虑增加基于论证的派遣斯卡拉,但只有当他可以删除在同一时间超载和向后兼容都与现有的Scala代码,使用重载和与Java兼容(他特别提到Swing和AWT在Java相当复杂的重载规则的每一个讨厌的暗角情况下,它们都发挥了一些极其复杂的技巧。我本人对向Ruby添加基于参数的分派有一些想法,但是我永远无法弄清楚如何以向后兼容的方式来实现它。
def method(a, b = true)
不起作用,因此方法重载是不可能的” 那样简单。不是; 这很难。我发现这个答案确实很有用。
我认为您正在寻找执行此操作的能力:
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'
希望能有所帮助
在使用静态类型的语言中,方法重载是有意义的,您可以在其中区分不同类型的参数
f(1)
f('foo')
f(true)
以及不同数量的参数之间
f(1)
f(1, 'foo')
f(1, 'foo', true)
红宝石不存在第一个区别。Ruby使用动态类型或“鸭子类型”。第二种区别可以通过默认参数或使用参数来处理:
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
),而不仅仅是类型。
但是您会发现使用此功能会降低性能;您将必须运行基准测试来确定您可以忍受的程度。
对于问题的原因,已经有了很好的答案。但是,如果有人在寻找其他解决方案,请查看功能红宝石,这是受Elixir 模式匹配功能启发的。
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!"