2012-04-04 17 views
37

sto attraversando Programming Ruby - a pragmatic programmers guide e sono imbattuti in questo pezzo di codice:Come funziona la definizione del metodo [parentesi quadra] in 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 

io non capisco come definiscono [] lavori di metodo?

Perché la chiave è all'esterno [], ma quando viene chiamato il metodo, è all'interno []?

La chiave può essere senza parentesi?

Mi rendo conto che ci sono modi migliori per scrivere questo, e sapere come scrivere il mio metodo che funziona, ma questo metodo [] appena mi sconcerta ... Ogni aiuto è molto apprezzato, grazie

risposta

35

Methods in rubino, a differenza di molte lingue può contenere alcuni caratteri speciali. Uno dei quali è la sintassi di ricerca degli array.

Se si dovesse implementare la propria classe hash in cui durante il recupero di un elemento in un hash, si voleva per invertire tale tendenza, si potrebbe fare la seguente:

class SillyHash < Hash 

    def [](key) 
    super.reverse 
    end 

end 

si può dimostrare questo chiamando un hash con il seguente:

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

Così il DEF [] definito il metodo che viene utilizzato quando si fa my_array["key"] Altri metodi che possono sembrare strano a voi sono:

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 

Giusto per chiarire, la definizione di un metodo [] non è correlata agli array o agli hash. Prendiamo il seguente esempio (forzato):

class B 
    def [] 
    "foo" 
    end 
end 

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

credo che il PO è stato chiesto il motivo per cui non si direbbe: ("chiave") 'my_array []' invece e come my_array [ "chiave"] potrebbe forse lavorare ... –

+0

quindi, per definizione, ogni volta che creo il metodo [] per una classe in ruby, sa che viene utilizzato su una sorta di array e prevede parametri (chiave) che verranno successivamente inseriti in []? – oFca

+0

@oFca Se definisci un metodo chiamato [], allora ti permetterà di chiamare '[" chiave "]' su un'istanza di quella classe. Una matrice o hash sono due esempi di dove Ruby lo utilizza internamente. – Gazler

8

le parentesi quadre sono il nome del metodo come Array#size avete Array#[] come metodo e anche si può utilizzare come qualsiasi altro metodo:

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

l'ultimo uno è simile allo zucchero sintattico e fa esattamente lo stesso del primo. Il Array#+ lavoro simile:

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

È anche possibile aggiungere i numeri in questo modo:

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

le stesse opere con /, *, - e molti altri.

39

È solo zucchero sintattico. Ci sono alcuni schemi di sintassi che vengono tradotti nelle mandate dei messaggi.In particolare

a + b 

è uguale

a.+(b) 

e lo stesso vale per ==, !=, <, >, <=, >=, <=>, ===, &, |, *, /, - , %, **, >>, <<, !==, =~ e !~ pure.

Inoltre,

!a 

è uguale

a.! 

e lo stesso vale per ~.

Poi,

+a 

è uguale

[email protected] 

e lo stesso vale per -.

Inoltre,

a.(b) 

è lo stesso di

a.call(b) 

C'è anche sintassi speciale per setter:

a.foo = b 

è lo stesso di

a.foo=(b) 

E, ultimo ma non meno importante, c'è sintassi speciale per l'indicizzazione:

a[b] 

è lo stesso di

a.[](b) 

e

a[b] = c 

è lo stesso di

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

La tua lista mi ha fatto pensare allo zucchero di Ruby. È interessante il fatto che l'interpolatore di stringhe '# {}' (ad esempio '" dì ciao, # {my_name} "') non sia zucchero per una chiamata al metodo. La prima pagina dall'indice del libro pick axe ha una bella lista. – SooDesuNe

+1

@SooDesuNe: It * fa * comunque chiama 'to_s'. –

0

È un overloader dell'operatore, sovrascrive o integra il comportamento di un metodo all'interno di una classe che hai definito, o una classe del comportamento che stai modificando. Puoi farlo ad altri operatori diversi da []. In questo caso stai modificando il comportamento di [] quando viene chiamato su qualsiasi istanza della classe SongList.

Se si ha songlist = SongList.nuovo e poi fai la lista canzoni ["foobar"] allora la tua def personalizzata entrerà in funzione e supporrà che "foobar" debba essere passato come parametro (chiave) e lo farà a "foobar" qualunque sia il metodo dice dovrebbe essere fatto per chiave.

Prova

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 
Problemi correlati