Réponses:
La surcharge de méthode peut être obtenue en déclarant deux méthodes avec le même nom et des signatures différentes. Ces différentes signatures peuvent être soit,
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
Nous ne pouvons pas réaliser de surcharge de méthode en utilisant la première méthode car il n'y a pas de déclaration de type de données dans ruby ( langage typé dynamique ). Donc, la seule façon de définir la méthode ci-dessus estdef(a,b)
Avec la deuxième option, il peut sembler que nous pouvons réaliser une surcharge de méthode, mais nous ne pouvons pas. Disons que j'ai deux méthodes avec un nombre d'arguments différent,
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.
Ainsi, ruby doit conserver une méthode dans la chaîne de recherche de méthode avec un nom unique.
"Surcharge" est un terme qui n'a tout simplement pas de sens dans Ruby. Il est essentiellement synonyme de « expédition basé argument statique », mais Ruby n'a pas avoir l' envoi statique du tout . Donc, la raison pour laquelle Ruby ne prend pas en charge la distribution statique basée sur les arguments, c'est qu'il ne prend pas en charge la distribution statique, point final. Il ne prend en charge aucune distribution statique , qu'elle soit basée sur des arguments ou autre.
Maintenant, si vous ne parlez pas spécifiquement de la surcharge, mais peut-être de la répartition dynamique basée sur des arguments, alors la réponse est: parce que Matz ne l'a pas implémentée. Parce que personne d'autre n'a pris la peine de le proposer. Parce que personne d'autre ne s'est donné la peine de le mettre en œuvre.
En général, une répartition dynamique basée sur des arguments dans un langage avec des arguments optionnels et des listes d'arguments de longueur variable est très difficile à obtenir correctement, et encore plus difficile à garder compréhensible. Même dans les langages avec une répartition statique basée sur des arguments et sans arguments optionnels (comme Java, par exemple), il est parfois presque impossible de dire pour un simple mortel, quelle surcharge va être choisie.
En C #, vous pouvez en fait encoder n'importe quel problème 3-SAT en résolution de surcharge, ce qui signifie que la résolution de surcharge en C # est NP-hard.
Maintenant, essayez cela avec une répartition dynamique , où vous avez la dimension de temps supplémentaire à garder dans votre tête.
Il existe des langages qui distribuent dynamiquement en fonction de tous les arguments d'une procédure, par opposition aux langages orientés objet, qui ne diffusent que sur l' self
argument zéro "caché" . Common Lisp, par exemple, distribue les types dynamiques et même les valeurs dynamiques de tous les arguments. Clojure distribue sur une fonction arbitraire de tous les arguments (ce qui BTW est extrêmement cool et extrêmement puissant).
Mais je ne connais aucun langage OO avec une répartition dynamique basée sur des arguments. Martin Odersky a déclaré qu'il pourrait envisager d'ajouter une répartition basée sur les arguments à Scala, mais seulement s'il peut supprimer la surcharge en même temps et être rétrocompatible avec le code Scala existant qui utilise la surcharge et compatible avec Java (il a notamment mentionné Swing et AWT qui jouent des trucs extrêmement complexes exerçant à peu près tous les cas obscurs méchants des règles de surcharge assez complexes de Java). J'ai moi-même eu des idées sur l'ajout d'une répartition basée sur des arguments à Ruby, mais je n'ai jamais pu comprendre comment le faire d'une manière rétrocompatible.
def method(a, b = true)
ne fonctionnera pas, donc la surcharge de méthode est impossible." Ce n'est pas; c'est juste difficile. J'ai cependant trouvé CETTE réponse très informative.
Je suppose que vous recherchez la capacité de le faire:
def my_method(arg1)
..
end
def my_method(arg1, arg2)
..
end
Ruby prend en charge cela d'une manière différente:
def my_method(*args)
if args.length == 1
#method 1
else
#method 2
end
end
Un modèle courant consiste également à passer des options sous forme de hachage:
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'
J'espère que cela pourra aider
La surcharge de méthode a du sens dans un langage à typage statique, où vous pouvez distinguer différents types d'arguments
f(1)
f('foo')
f(true)
ainsi qu'entre différents nombres d'arguments
f(1)
f(1, 'foo')
f(1, 'foo', true)
La première distinction n'existe pas dans le rubis. Ruby utilise le typage dynamique ou "typage canard". La deuxième distinction peut être gérée par des arguments par défaut ou en travaillant avec des arguments:
def f(n, s = 'foo', flux_compensator = true)
...
end
def f(*args)
case args.size
when
...
when 2
...
when 3
...
end
end
Cela ne répond pas à la question de savoir pourquoi ruby n'a pas de surcharge de méthode, mais des bibliothèques tierces peuvent la fournir.
La bibliothèque contracts.ruby permet la surcharge. Exemple adapté du tutoriel:
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
Notez que c'est en fait plus puissant que la surcharge de Java, car vous pouvez spécifier des valeurs à faire correspondre (par exemple 1
), pas simplement des types.
Vous verrez cependant des performances réduites en utilisant ceci; vous devrez exécuter des benchmarks pour décider de ce que vous pouvez tolérer.
Je fais souvent la structure suivante:
def method(param)
case param
when String
method_for_String(param)
when Type1
method_for_Type1(param)
...
else
#default implementation
end
end
Cela permet à l'utilisateur de l'objet d'utiliser la méthode clean and clear nom_méthode: méthode Mais s'il souhaite optimiser l'exécution, il peut directement appeler la méthode correcte.
En outre, cela rend votre test plus clair et meilleur.
il y a déjà de bonnes réponses du côté pourquoi de la question. Cependant, si vous recherchez d'autres solutions, consultez la gemme rubis fonctionnelle qui est inspirée des fonctionnalités de correspondance de motifs 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!"