Ответы:
Перегрузка методов может быть достигнута путем объявления двух методов с одинаковыми именами и разными сигнатурами. Эти разные подписи могут быть
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!"