2009-04-20 12 views
5

Supongamos que usted hace esto en Ruby:hacer que un objeto se comporta como una matriz para la asignación paralelo en rubí

ar = [1, 2] 
x, y = ar 

Entonces, x == 1 ey == 2. ¿Existe un método que pueda definir en mi propias clases que producirán el mismo efecto? p.ej.

rb = AllYourCode.new 
x, y = rb 

Hasta ahora, todo lo que he podido ver con una misión como esta es hacer x == y = Rb y nula. Python tiene una función como esta:

>>> class Foo: 
...  def __iter__(self): 
...    return iter([1,2]) 
... 
>>> x, y = Foo() 
>>> x 
1 
>>> y 
2 
+0

perfecto, gracias, esto es justo lo que necesito en este momento. –

Respuesta

7

Sí. Defina #to_ary. Esto permitirá que su objeto sea tratado como una matriz para la asignación.

irb> o = Object.new 
=> #<Object:0x3556ec> 
irb> def o.to_ary 
     [1, 2] 
    end 
=> nil 
irb> x, y = o 
=> [1,2] 
irb> x 
#=> 1 
irb> y 
#=> 2 

La diferencia entre #to_a y #to_ary es que #to_a se usa para tratar de convertir un objeto dado a una matriz, mientras que #to_ary está disponible si podemos tratar el objeto dado como una matriz. Es una diferencia sutil.

+0

Sutilmente; esta es una distinción similar entre == y eql? que realmente no me gusta ¿Por qué es una buena idea tener to_a AND to_ary ??? – allyourcode

+1

to_ary es para objetos que son efectivamente matrices. Si algo que realmente necesita usar una matriz puede usar su objeto en lugar de una matriz y su objeto debe ser una matriz, entonces debe implementar to_ary. to_a es para cosas que son convertibles en matrices, p. objetos con (terminación) cada método tiene una implementación obvia de to_a. P.ej. un archivo puede tener un método to_a, pero no puede tratarlo como una matriz, y no modela una matriz para que no tenga un método to_ary. –

1

No se puede redefinir la misión, porque es un operador en lugar de un método. Pero si tu clase AllYourCode fuera a heredar de Array, tu ejemplo funcionaría.

Cuando Ruby encuentra una tarea, mira a la derecha y si hay más de un valor r, los recopila en una matriz. Luego mira hacia el lado izquierdo. Si hay un valor l allí, se le asigna la matriz.

def foo 
    return "a", "b", "c" # three rvalues 
end 

x = foo # => x == ["a", "b", "c"] 

Si hay más de un valor-i (más específicamente, si ve una coma), se asigna rvalues ​​sucesiva y descarta los extras.

x, y, z = foo # => x == "a", y == "b", z == "c" 
x, y = foo # => x == "a", y == "b" 
x, = foo  # => x == "a" 

Usted puede hacer la asignación paralelo si se devuelve una matriz, también, como usted ha descubierto.

def bar 
    ["a", "b", "c"] 
end 

x = bar  # => x == ["a", "b", "c"] 
x, y, z = bar # => x == "a", y == "b", z == "c" 
x, y = bar # => x == "a", y == "b" 
x, = bar  # => x == "a" 

Así que en su ejemplo, si RB es una matriz o herede de Array, x e y se le asignará sus primeros 2 valores.

+0

Creo que quisiste poner corchetes alrededor de "a", "b", "c" en tu primer ejemplo. Cuando lo probé, obtuve un error de sintaxis. – allyourcode

+0

En realidad, olvidé el "retorno". Corregido ahora. –

2

Casi:

class AllYourCode 
    def to_a 
    [1,2] 
    end 
end 

rb = AllYourCode.new 
x, y = *rb 
p x 
p y 

Splat intentará invocar to_ary, y luego tratar de invocar to_a. No estoy seguro de por qué quieres hacer esto, sin embargo, esta es realmente una característica sintáctica que usa Array en su implementación, en lugar de una función de Array.

En otras palabras los casos de uso de la asignación múltiple son cosas como:

# swap 
x, y = y, x 

# multiple return values 
quot, rem = a.divmod(b) 

# etc. 
name, age = "Person", 100 

En otras palabras, la mayoría de las veces el objeto que se asigna a partir de (la Array) no es aún evidente.

+2

Esto es algo útil, pero lo odio cuando hago una pregunta y la gente cree que no tengo una buena razón para hacer lo que estoy tratando de hacer. Si crees que esta es una mala idea, explica por qué !! Aprecio tus ejemplos, pero mostrar los usos típicos no explica qué está mal con lo que estoy tratando de hacer:/ – allyourcode

+0

No dije que no tenías una buena razón, solo dije que no sé cuál es tu La razón es. No puedo opinar sobre si es bueno o no hasta que sepa de qué se trata. Ciertamente, no puedo decir que nunca haya una circunstancia en la que quieras hacer esto, pero si te complaces con mi curiosidad, te lo agradecería. –

Cuestiones relacionadas