Jawaban:
Metode overloading dapat dicapai dengan mendeklarasikan dua metode dengan nama yang sama dan tanda tangan yang berbeda. Tanda tangan yang berbeda ini bisa berupa,
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
Kami tidak dapat mencapai metode overload menggunakan cara pertama karena tidak ada deklarasi tipe data di ruby ( bahasa pengetikan dinamis ). Jadi satu-satunya cara untuk mendefinisikan metode di atas adalahdef(a,b)
Dengan opsi kedua, sepertinya kita bisa mencapai metode overloading, tetapi kita tidak bisa. Katakanlah saya memiliki dua metode dengan jumlah argumen yang berbeda,
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.
Jadi ruby perlu mempertahankan satu metode dalam metode mencari rantai dengan nama yang unik.
"Kelebihan beban" adalah istilah yang bahkan tidak masuk akal di Ruby. Ini pada dasarnya adalah sinonim untuk "pengiriman berbasis argumen statis", tetapi Ruby tidak memiliki pengiriman statis sama sekali . Jadi, alasan mengapa Ruby tidak mendukung pengiriman statis berdasarkan argumen, adalah karena Ruby tidak mendukung pengiriman statis, titik. Itu tidak mendukung pengiriman statis dalam bentuk apa pun , baik berbasis argumen atau sebaliknya.
Sekarang, jika Anda tidak benar-benar secara spesifik bertanya tentang kelebihan muatan, tetapi mungkin tentang pengiriman berbasis argumen dinamis , maka jawabannya adalah: karena Matz tidak mengimplementasikannya. Karena tidak ada orang lain yang mau mengusulkannya. Karena tidak ada orang lain yang peduli untuk mengimplementasikannya.
Secara umum, pengiriman berbasis argumen dinamis dalam bahasa dengan argumen opsional dan daftar argumen panjang variabel, sangat sulit untuk diperbaiki, dan bahkan lebih sulit untuk membuatnya dimengerti. Bahkan dalam bahasa dengan pengiriman berbasis argumen statis dan tanpa argumen opsional (seperti Java, misalnya), kadang-kadang hampir tidak mungkin untuk mengatakan untuk manusia biasa, yang kelebihan beban akan dipilih.
Dalam C #, Anda benar-benar dapat menyandikan masalah 3-SAT ke resolusi kelebihan beban, yang berarti bahwa resolusi kelebihan beban di C # adalah NP-hard.
Sekarang coba dengan pengiriman dinamis , di mana Anda memiliki dimensi waktu tambahan untuk tetap di kepala Anda.
Ada bahasa yang secara dinamis mengirimkan berdasarkan semua argumen prosedur, sebagai lawan dari bahasa berorientasi objek, yang hanya mengirim pada "nol" self
argumen yang tersembunyi . Lisp umum, misalnya, mengirimkan tipe dinamis dan bahkan nilai dinamis semua argumen. Clojure mengirimkan fungsi sewenang-wenang dari semua argumen (yang BTW sangat keren dan sangat kuat).
Tapi saya tidak tahu bahasa OO dengan pengiriman berbasis argumen yang dinamis. Martin Odersky mengatakan bahwa ia mungkin mempertimbangkan untuk menambahkan pengiriman berbasis argumen ke Scala, tetapi hanya jika ia dapat menghapus kelebihan muatan pada saat yang sama dan kompatibel dengan keduanya dengan kode Scala yang ada yang menggunakan kelebihan muatan dan kompatibel dengan Java (ia terutama menyebut Swing dan AWT yang memainkan beberapa trik yang sangat kompleks dengan melakukan hampir setiap kasus sudut gelap yang buruk dari aturan overload yang agak rumit dari Java) Saya sendiri memiliki beberapa ide tentang menambahkan pengiriman berbasis argumen ke Ruby, tetapi saya tidak pernah tahu bagaimana melakukannya dengan cara yang kompatibel dengan mundur.
def method(a, b = true)
tidak akan bekerja, oleh karena itu metode overloading tidak mungkin." Ini bukan; itu hanya sulit. Namun, saya menemukan jawaban ini sangat informatif.
Saya kira Anda sedang mencari kemampuan untuk melakukan ini:
def my_method(arg1)
..
end
def my_method(arg1, arg2)
..
end
Ruby mendukung ini dengan cara yang berbeda:
def my_method(*args)
if args.length == 1
#method 1
else
#method 2
end
end
Pola umum juga untuk meneruskan opsi sebagai 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'
Semoga itu bisa membantu
Metode overloading masuk akal dalam bahasa dengan pengetikan statis, di mana Anda dapat membedakan berbagai jenis argumen
f(1)
f('foo')
f(true)
serta antara jumlah argumen yang berbeda
f(1)
f(1, 'foo')
f(1, 'foo', true)
Perbedaan pertama tidak ada di ruby. Ruby menggunakan pengetikan dinamis atau "pengetikan bebek". Perbedaan kedua dapat ditangani oleh argumen default atau dengan bekerja dengan argumen:
def f(n, s = 'foo', flux_compensator = true)
...
end
def f(*args)
case args.size
when
...
when 2
...
when 3
...
end
end
Ini tidak menjawab pertanyaan mengapa ruby tidak memiliki kelebihan metode, tetapi perpustakaan pihak ketiga dapat menyediakannya.
The contracts.ruby perpustakaan memungkinkan overloading. Contoh diadaptasi dari tutorial:
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
Perhatikan bahwa ini sebenarnya lebih kuat daripada kelebihan beban Java, karena Anda dapat menentukan nilai yang cocok (misalnya 1
), bukan hanya tipe.
Anda akan melihat penurunan kinerja menggunakan ini; Anda harus menjalankan tolok ukur untuk memutuskan seberapa banyak Anda bisa mentolerir.
Saya sering melakukan struktur berikut:
def method(param)
case param
when String
method_for_String(param)
when Type1
method_for_Type1(param)
...
else
#default implementation
end
end
Ini memungkinkan pengguna objek untuk menggunakan method_name: metode yang bersih dan jelas. Tetapi jika ia ingin mengoptimalkan eksekusi, ia dapat langsung memanggil metode yang benar.
Juga, itu membuat tes Anda lebih jelas dan lebih baik.
sudah ada jawaban bagus mengapa dari sisi pertanyaan. Namun, jika ada yang mencari solusi lain, periksa permata fungsional-ruby yang terinspirasi oleh fitur pencocokan pola 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!"