2012-12-19 9 views
5

Probabilmente non è qualcosa che dovresti provare a casa, ma per qualche ragione ho tentato di creare una serie di metodi in Ruby.Ruby: metodi come elementi dell'array - come funzionano?

Ho iniziato definendo due metodi.

irb(main):001:0> def test1 
irb(main):002:1> puts "test!" 
irb(main):003:1> end 
=> nil 
irb(main):004:0> def test2 
irb(main):005:1> puts "test2!" 
irb(main):006:1> end 
=> nil 

La cosa strana si verifica quando si tenta di inserirlo in un array reale. Sembra che esegua entrambi i metodi.

irb(main):007:0> array = [test1, test2] 
test! 
test2! 
=> [nil, nil] 

E in seguito, la matrice è vuota.

irb(main):008:0> puts array 


=> nil 

Qualcuno può spiegarmi perché esegue i metodi? A parte questo, l'intero esercizio ha davvero bisogno di un esorcista?

risposta

14

Quello che stai memorizzando nel tuo array è il risultato di chiamare i tuoi metodi, non i metodi stessi.

def test1 
    puts "foo!" 
end 

def test2 
    puts "bar!" 
end 

È possibile memorizzare i riferimenti ai metodi attuali come questo:

> arr = [method(:test1), method(:test2)] 
# => [#<Method: Object#test1>, #<Method: Object#test2>] 

In seguito, è possibile chiamare i metodi di riferimento in questo modo:

> arr.each {|m| m.call } 
foo! 
bar! 
+0

Oh, quindi è possibile. Bello! – Nekkoru

1

Se tu avessi un metodo square e ha voluto creare un array con i valori quadrati di 2 e 4, si può scrivere

array = [square(2), square(4)] 

Qui si sta facendo esattamente la stessa cosa, solo che i tuoi metodi di prova don Non restituire nulla ed è per questo che il tuo array finale sembra vuoto (in realtà, contiene [nil, nil]).

+0

Le definizioni dei metodi in questo caso restituiscono 'nil', come mostrato. L'OP ha torto nel dire che è diventato vuoto; non lo è. Sono state stampate righe vuote che rappresentano le due istanze di 'nil' che l'array ha. – sawa

+0

@sawa Hai ragione, la mia risposta non era abbastanza precisa. Ho modificato – alestanis

1

L'array non contiene mai nient'altro che due valori nulli. Ti inganno mettendo le corde al momento della valutazione. Ma il valore di ritorno di ogni funzione è ancora zero.

1

Il tuo codice esegue i due metodi perché in effetti stai chiamando i metodi quando dici "test1" e "test2" - le parentesi sono facoltative per le chiamate al metodo ruby.

Poiché entrambi i metodi contengono solo un "puts", che restituisce zero, l'array risultante è solo un array di due nils.

3

@alestanis spiegato bene la ragione. Se si stavano cercando di memorizzare i metodi, allora si può fare quello che dice Lars Haugseth o si potrebbe fare la folllowing:

test1 = Proc.new { puts "test!" } 
test2 = Proc.new { puts "test2!" } 
a = [test1, test2] 

Questo può rendere il codice molto più leggibile.

Ecco una corsa irb.

1.9.3p194 :009 > test1 = Proc.new { puts "test!" } 
=> #<Proc:[email protected](irb):9> 
1.9.3p194 :010 > test2 = Proc.new { puts "test2!" } 
=> #<Proc:[email protected](irb):10> 
1.9.3p194 :011 > a = [test1, test2] 
=> [#<Proc:[email protected](irb):9>, #<Proc:[email protected](irb):10>] 
0

Ecco i miei due centesimi. Basandosi sulle soluzioni già pubblicate, questo è un esempio di un esempio funzionante. Quello che potrebbe essere utile per alcuni qui è che include gli argomenti del metodo e l'uso di self (che si riferisce all'istanza della classe PromotionalRules quando viene istanziata) e l'array di simboli, che è pulito - L'ho ottenuto dai documenti Ruby sul metodo #send here. Spero che questo aiuti qualcuno!

class PromotionalRules 
    PROMOTIONS = [:lavender_heart_promotion, :ten_percent_discount] 

    def apply_promotions total, basket 
    @total = total 

    if PROMOTIONS.count > 0 
     PROMOTIONS.each { |promotion| @total = self.send promotion, @total, basket } 
    end 

    @total.round(2) 
    end 

    def lavender_heart_promotion total, basket 
    if two_or_more_lavender_hearts? basket 
     basket.map { |item| total -= 0.75 if item == 001 } 
    end 
    total 
    end 

    def two_or_more_lavender_hearts? basket 
    n = 0 
    basket.each do |item| 
     n += 1 if item == 001 
    end 
    n >= 2 
    end 

    def ten_percent_discount total, *arg 
    if total > 60.00 
     total = total - total/10 
    end 
    total 
    end 
end 

Grazie a tutti per il loro aiuto. Adoro la natura open source della codifica - i thread diventano sempre migliori mentre le persone si iterano sulle reciproche soluzioni!