2012-04-04 13 views
37

estoy pasando por Programming Ruby - a pragmatic programmers guide y han tropezado en este pedazo de código:¿Cómo funciona el método de definición [corchete cuadrado] en Ruby?

class SongList 
    def [](key) 
    if key.kind_of?(Integer) 
     return @songs[key] 
    else 
     for i in [email protected] 
     return @songs[i] if key == @songs[i].name 
     end 
    end 
    return nil 
    end 
end 

No entiendo cómo definen [] funciona el método?

¿Por qué la clave está fuera de [], pero cuando se llama al método, está dentro de []?

¿Puede la clave estar sin paréntesis?

Soy consciente de que hay mucho mejores maneras de escribir esto, y saber cómo escribir mi propio método que funciona, pero este método [] simplemente me desconcierta ... Cualquier ayuda es muy apreciada, gracias

Respuesta

35

Métodos de Ruby, a diferencia de muchos idiomas, puede contener algunos caracteres especiales. Una de ellas es la sintaxis de búsqueda de matriz.

Si se va a poner en práctica su propia clase de hash, donde al recuperar un artículo en su hachís, que quería darle la vuelta, se puede hacer lo siguiente:

class SillyHash < Hash 

    def [](key) 
    super.reverse 
    end 

end 

Usted puede probar esto llamando a un hash con lo siguiente:

a = {:foo => "bar"} 
=> {:foo=>"bar"} 
a.[](:foo) 
=> "bar" 
a.send(:[], :foo) 
=> "bar" 

Así que la definición [] se define el método que se utiliza cuando se hace my_array["key"] Otros métodos que pueden parecer extraño para usted son:

class SillyHash < Hash 

    def [](key) 
    super.reverse 
    end 

    def []=(key, value) 
    #do something 
    end 

    def some_value=(value) 
    #do something 
    end 

    def is_valid?(value) 
    #some boolean expression 
    end 

end 

Solo para aclarar, la definición de un método [] no está relacionada con arreglos o hash. Tomemos el ejemplo siguiente (artificial):

class B 
    def [] 
    "foo" 
    end 
end 

B.new[] 
=> "foo" 
+1

creo que la OP se pregunta por qué no podríamos llamarlo: 'my_array ("llave") []' en lugar y cómo my_array [ "clave"] podría trabajar posiblemente ... . –

+0

entonces, por definición, cada vez que creo el método [] para alguna clase en ruby, sabe que se está utilizando en algún tipo de matriz y espera el parámetro (clave) que luego pone en []? – oFca

+0

@oFca Si define un método llamado [], le permitirá llamar a '[" clave "]' en una instancia de esa clase. Un Array o Hash son dos ejemplos de donde Ruby usa esto internamente. – Gazler

8

los corchetes son el nombre de método como Array#size tiene Array#[] como método e incluso se puede utilizar como cualquier otro método:

array = [ 'a', 'b', 'c'] 
array.[](0) #=> 'a' 
array.[] 1 #=> 'b' 
array[2] #=> 'c' 

la última uno es algo así como azúcar sintáctico y hace exactamente lo mismo que el primero. El trabajo Array#+ similar:

array1 = [ 'a', 'b' ] 
array2 = [ 'c', 'd' ] 
array1.+(array2) #=> [ 'a', 'b', 'c', 'd' ] 
array1.+ array2 #=> [ 'a', 'b', 'c', 'd' ] 
array1 + array2 #=> [ 'a', 'b', 'c', 'd' ] 

Usted puede incluso agregar números de la siguiente manera:

1.+(1) #=> 2 
1.+ 1 #=> 2 
1 + 1 #=> 2 

las mismas obras con /, *, - y muchos más.

39

Es azúcar sintáctico. Hay ciertos patrones de sintaxis que se traducen en envíos de mensajes.En particular

a + b 

es la misma que

a.+(b) 

y lo mismo se aplica a ==, !=, <, >, <=, >=, <=>, ===, &, |, *, /, - , %, **, >>, <<, !==, =~ y !~ también.

Además,

!a 

es lo mismo que

a.! 

y lo mismo se aplica a ~.

Entonces,

+a 

es lo mismo que

[email protected] 

y lo mismo se aplica a -.

Plus,

a.(b) 

es la misma que

a.call(b) 

También hay una sintaxis especial para los emisores:

a.foo = b 

es lo mismo que

a.foo=(b) 

Y por último pero no menos importante, hay una sintaxis especial para la indexación:

a[b] 

es el mismo que

a.[](b) 

y

a[b] = c 

es la misma que

a.[]=(b, c) 
+0

Tu lista me hizo pensar en el azúcar de Ruby. Es interesante que el interpolador de cadena '# {}' (por ejemplo '" say hola, # {mi_nombre} "') no sea útil para una llamada a método. La primera página del índice del libro de hacha tiene una buena lista. – SooDesuNe

+1

@SooDesuNe: It * does * sin embargo llama a 'to_s'. –

0

Es un supercargador de operador, anula o complementa el comportamiento de un método dentro de una clase que haya definido, o una clase cuyo comportamiento está modificando. Puede hacerlo a otros operadores diferentes de []. En este caso, está modificando el comportamiento de [] cuando se invoca en cualquier instancia de la lista SongList.

Si tiene songlist = SongList.nuevo y luego haces songlist ["foobar"] luego tu def personalizada entrará en funcionamiento y asumirá que "foobar" se pasará como el parámetro (clave) y hará "foobar" lo que diga el método debe hacerse a la clave.

Trate

class Overruler 
    def [] (input) 
      if input.instance_of?(String) 
      puts "string" 
      else 
      puts "not string" 
      end 
    end 
end 
foo = Overruler.new 
foo["bar"].inspect 
foo[1].inspect 
Cuestiones relacionadas