Ответы:
Перегрузка методов может быть достигнута путем объявления двух методов с одинаковыми именами и разными сигнатурами. Эти разные подписи могут быть
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 не поддерживает статическую диспетчеризацию на основе аргументов, заключается в том, что она не поддерживает статическую диспетчеризацию, точка. Он не поддерживает статическую диспетчеризацию любого типа , основанную на аргументах или иным образом.
Теперь, если вы не на самом деле конкретно спрашивать о перегрузке, но , может быть , о динамическом аргументе на основе отправки, то ответ: потому что Мацы не реализовали его. Потому что никто не удосужился предложить это. Потому что никто не удосужился реализовать это.
В целом, динамическая диспетчеризация на основе языка в языке с необязательными аргументами и списками аргументов переменной длины очень трудно понять правильно, и еще труднее сделать ее понятной. Даже в языках со статической диспетчеризацией, основанной на аргументах, и без дополнительных аргументов (например, в Java), иногда почти невозможно сказать для простого смертного, какая перегрузка будет выбрана.
В C # вы можете фактически закодировать любую проблему 3-SAT в разрешение перегрузки, что означает, что разрешение перегрузки в C # является NP-сложным.
Теперь попробуйте это с динамической диспетчеризацией, где у вас есть дополнительное измерение времени, которое нужно держать в голове.
Существуют языки, которые динамически распределяются на основе всех аргументов процедуры, в отличие от объектно-ориентированных языков, которые отправляют только по «скрытому» нулевому selfаргументу. Common Lisp, например, отправляет динамические типы и даже динамические значения всех аргументов. Clojure рассылает произвольную функцию от всех аргументов (что, кстати, чрезвычайно круто и чрезвычайно мощно).
Но я не знаю ни одного языка OO с динамической диспетчеризацией на основе аргументов. Мартин Одерски сказал, что он мог бы рассмотреть возможность добавления диспетчеризации на основе аргументов в Scala, но только если он может одновременно устранить перегрузку и быть обратно совместимым как с существующим кодом 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 нет перегрузки методов, но сторонние библиотеки могут это предоставить.
Библиотека contract.ru позволяет перегружать. Пример адаптирован из учебника:
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 ), а не просто типы.
Вы увидите снижение производительности при использовании этого, хотя; вам придется запустить тесты, чтобы решить, сколько вы можете терпеть.
Я часто делаю следующую структуру:
def method(param)
case param
when String
method_for_String(param)
when Type1
method_for_Type1(param)
...
else
#default implementation
end
end
Это позволяет пользователю объекта использовать чистый и понятный method_name: метод. Но если он хочет оптимизировать выполнение, он может напрямую вызвать правильный метод.
Кроме того, это делает ваши тесты яснее и лучше.
Уже есть отличные ответы на вопрос, почему сторона вопроса. однако, если кто-то ищет другие решения, обратите внимание на функциональную рубиновую жемчужину, которая вдохновлена возможностями сопоставления с образцом 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!"