Відповіді:
Перевантаження методу можна досягти, оголосивши два методи з однаковим іменем та різними підписами. Ці різні підписи можуть бути або
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
Ми не можемо домогтися перевантаження методу, використовуючи перший спосіб, оскільки в рубіні не існує декларації про тип даних ( динамічна набрана мова ). Тож єдиним способом визначити вищевказаний метод є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 не підтримує статичну відправлення на основі аргументів, полягає в тому, що вона не підтримує статичну диспетчеризацію, період. Він не підтримує статичну диспетчеризацію будь-якого виду , на основі аргументів чи іншим чином.
Тепер, якщо ви насправді не конкретно запитуєте про перевантаження, але, можливо, про динамічну розсилку на основі аргументів, то відповідь: тому що Матц не реалізував це. Тому що ніхто більше не намагався її запропонувати. Тому що ніхто інший не намагався його здійснити.
Загалом, динамічне відправлення на основі аргументів мовою з необов'язковими аргументами та списками аргументів змінної довжини дуже важко отримати правильне значення, а ще важче - зробити його зрозумілим. Навіть у мовах зі статичною аргументацією на основі аргументів і без необов'язкових аргументів (наприклад, Java), іноді майже неможливо сказати простому смертному, який буде перевантажено.
У C # ви можете фактично кодувати будь -яку проблему 3-SAT в роздільній здатності перевантаження, а це означає, що роздільна здатність перевантаження в C # є важкою для NP.
Тепер спробуйте це з динамічним відправленням, де у вас є додатковий часовий вимір, який потрібно тримати в голові.
Є мови, які динамічно розсилаються на основі всіх аргументів процедури, на відміну від об'єктно-орієнтованих мов, які розсилаються лише на "прихованому" нульовому self
аргументі. Наприклад, звичайний Lisp розсилає динамічні типи і навіть динамічні значення всіх аргументів. Clojure посилає на довільну функцію всіх аргументів (що BTW надзвичайно круто і надзвичайно потужно).
Але я не знаю жодної мови ОО з динамічною розсилкою на основі аргументів. Мартін Одерський сказав, що він може розглянути можливість додавання на основі аргументів відправки до Scala, але тільки якщо він може одночасно зняти перевантаження і бути зворотним сумісним як із існуючим кодом Scala, який використовує перевантаження, так і сумісний з Java (він особливо згадував Swing та AWT які грають деякі надзвичайно складні трюки, виконуючи майже кожен неприємний темний кутовий випадок досить складних правил перевантаження Java. Я сам мав кілька ідей щодо додавання на Рубі відправлення на основі аргументів, але я ніколи не міг зрозуміти, як це зробити зворотно сумісним способом.
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)
Перша відмінність не існує в рубіні. Рубі використовує динамічний набір тексту або "набирання качок". Друге відмінність може бути оброблене за допомогою аргументів за замовчуванням або за допомогою аргументів:
def f(n, s = 'foo', flux_compensator = true)
...
end
def f(*args)
case args.size
when
...
when 2
...
when 3
...
end
end
Це не відповідає на питання, чому у ruby немає перевантаження методом, але сторонні бібліотеки можуть його надати.
Бібліотека контрактів.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!"