44 votes

Méthode d'envoi en Ruby

Je viens de lire ce que send en Ruby et je suis toujours confus en regardant ce code (il provient d'un quiz mais sa date d'échéance est dépassée de toute façon).

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

Je comprends que la première ligne assigne un tableau à x alors je ne comprends pas ce que :[] = ,0,2 ne fait rien du tout et je ne comprends pas pourquoi envoyer est nécessaire à cet endroit. Je ne comprends pas ce que x.[](1) fait et x.send( :[],2) fait sur la dernière ligne

Je suis vraiment confus et je ne trouve pas cette information en ligne.

J'ai trouvé le quoi envoyer fait mais je suis toujours un peu confus et très confus à propos de ce code dans son ensemble.

57voto

Chris Heald Points 28814

Tout d'abord, des choses comme [] (indice du tableau) et []= sont juste des méthodes en Ruby. x est un Array et les tableaux ont un []= qui accepte deux arguments, un indice et une valeur à définir.

Utilisation de send vous permet de passer un "message" arbitraire (appel de méthode) à un objet, avec des paramètres arbitraires.

Vous pourriez appeler x.send :sort par exemple, pour envoyer le message "sort" au tableau. Sort n'a pas besoin de paramètres, donc nous n'avons pas besoin de lui passer quoi que ce soit d'autre.

x#[]= d'autre part, accepte deux arguments. Sa méthode peut ressembler à ceci :

def []=(index, value)
  self.set_value_at_index(index, value)
end

Donc, nous pouvons simplement l'invoquer avec send :[]=, 0, 2 ce qui revient à appeler x[0] = 2 . Neat, huh ?

24voto

Eureka Points 1647

En Ruby, a[0] = 2 est en fait un sucre syntaxique pour a.[]=(0, 2) .

Sachant cela, c'est ce que fait votre seconde ligne - elle appelle le []= avec deux arguments en utilisant la métaprogrammation, comme vous l'avez correctement deviné.

Il en va de même pour votre troisième ligne : a[0] est un sucre syntaxique dans Ruby pour x.[](0) .

Le code suivant est un équivalent plus simple de votre exemple :

x = [1, 2, 3]
x[0] = 2
x[0] + x[1] + x[2]

21voto

Jefffrey Points 31698

Ne vous inquiétez pas. Ruby peut être un peu délicat dans ces cas-là. Examinons le code ligne par ligne :

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

Première ligne

La première ligne est claire pour vous : elle attribue un tableau de trois éléments à x. Et c'est à peu près tout.

Deuxième ligne

La deuxième ligne appelle le Object#send méthode de x en passant un symbole (rappelez-vous que tout ce qui commence par : est un symbole en ruby) :[]= , 0 (a Fixnum ) et 2 (un autre Fixnum ).
Il ne vous reste plus qu'à examiner ce que fait la méthode send (comme vous avez dit l'avoir déjà fait) :

Appelle la méthode identifiée par le symbole, en lui passant les arguments spécifiés.

Cela signifie qu'il invoquera la méthode identifiée par :[]= et passer 0 y 2 à elle. Voyons maintenant le Array#[]= méthode. Cette définition de méthode (qui peut être surchargé par vous si vous avez besoin de le faire) est :

class Array
    # ...
    def []=(a, b)
        # ...
    end
end

Cette méthode est appelée par send como x.[]=(0, 2) ce qui est plutôt moche si vous voulez mon avis. C'est pourquoi Ruby définit une version de sucre syntaxique : x[0] = 2 et en général :

x.[]=(a, b)  -->  x[a] = b

Dans le Array nous avons aussi le cas suivant :

x.[](a)  -->  x[a]

Dans les deux cas, vous êtes libre d'appeler la version qui vous semble la plus logique dans le contexte spécifique.

Troisième ligne

Maintenant, la troisième et dernière ligne :

x[0] + x.[](1) + x.send(:[],2)

les choses deviennent vraiment compliquées. Divisons-le en deux :

  1. x[0]
  2. x.[](1)
  3. x.send(:[], 2)

La première est assez simple. Elle renvoie le premier élément du tableau.

Le second est le sucre syntaxique que nous avons vu précédemment et qui peut être essentiellement converti en x[1] qui renvoie le deuxième élément du tableau.

Le troisième utilise Object#send pour appeler la méthode [] en passant par 2 à celui-ci. Ce qui signifie qu'il appelle x.[](2) ce qui signifie x[2] .

Conclusion

Le code

x = [1,2,3]
x.send :[]=,0,2
x[0] + x.[](1) + x.send(:[],2)

peut être converti en utilisant :

x.send(:[]=, a, b)  -->  x.[]=(a, b)
x.send(:[], a)  -->  x.[](a)
x.[]=(a, b)  -->  x[a] = b
x.[](a)  -->  x[a]

à :

x = [1,2,3]
x[0] = 2
x[0] + x[1] + x[2]

qui peut être réduit à :

2 + 2 + 3

ce qui entraîne :

7

7voto

Boris Strandjev Points 18480

send est un moyen de réaliser des appels de réflexion en ruby. Ainsi cette ligne :

x.send :[]=,0,2

Est équivalent à :

x[0] = 2

vous l'avez lu de cette façon : le nom de la méthode est le symbole (dans votre cas []= ) et ensuite vous passez les paramètres - 0 et 2.

2voto

user2592489 Points 29

X[0]+x[1]+x[2]=2+2+3=7 Je suppose que ce doit être la réponse

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X