2010-06-15 7 views
5

Sagen wir, ich habe eine FunktionVerständnis Ruby-Enumerable # Karte (mit komplexeren Blöcke)

def odd_or_even n 
    if n%2 == 0 
    return :even 
    else 
    return :odd 
    end 
end 

Und ich hatte eine einfache enumerable Array

simple = [1,2,3,4,5] 

Und ich lief es durch Karte, mit meinem Funktion, mit einem do-End-Block:

simple.map do 
    |n| odd_or_even(n) 
end 
# => [:odd,:even,:odd,:even,:odd] 

Wie könnte ich dies tun, ohne, sagen wir, die Funktion in erster Linie zu definieren? Zum Beispiel

ist nicht gültig Ruby, und der Compiler wird wütend auf mich für sogar darüber nachzudenken. Aber wie würde ich eine gleichwertige Sache umsetzen, das funktioniert?

bearbeiten

In Wirklichkeit mir die Lösung für mein Problem zählt, viel weniger als die Motivation/Argumentation dahinter, mir zu helfen, zu verstehen, wie Rubin Blöcke arbeiten :)

+2

Für das, was es wert ist, Sie Kann 1. sogar tun? oder 1.odd in ruby> = 1.8.7 – steenslag

Antwort

13

Sie‘ So nah. Entferne einfach die return s und du bist golden.

Das ist, weil der Block, der an map übergeben wird, ein Proc ist (d. H. Erstellt mit Proc.new), und nicht ein Lambda. Ein return innerhalb eines Proc springt nicht nur aus dem Prozess, sondern springt aus der Methode heraus, die den Prozess ausführt (d. H. call an). Eine Rendite innerhalb eines Lambda hingegen springt nur aus dem Lambda heraus.

Die Methode proc gibt ein Lambda in Ruby 1.8 und einen Proc in Ruby 1.9 zurück. Es ist wahrscheinlich am besten, diese Methode nicht zu verwenden und explizit anzugeben, welches Konstrukt Sie verwenden möchten.

Ich vermute, Sie waren entweder in IRB oder ein einfaches Ruby-Skript, wenn Sie dies ausprobiert haben.

Die Lektion daraus zu lernen ist, implizite Renditen zu verwenden, es sei denn, Sie können nicht, denke ich.

+0

Gibt es einen Grund * warum * das passiert? Gibt der Block einfach den zuletzt ausgeführten Befehl aus, wie bei impliziten Returns? Ich frage das, weil ich gerne vorhersagen könnte, was passiert; diese herauskommen scheint nur ein bisschen ... zufällig. –

+0

Die kurze Version ist "es ist einer der Unterschiede zwischen Procs und Lambdas." Arbeiten an einer besseren Erklärung. Und ja, Blöcke werden nur den zuletzt ausgewerteten Ausdruck in ihnen zurückgeben. – x1a4

+0

danke für die Erklärung; es ist sehr gründlich und hilfreich =) nur eine letzte Frage ... ist es möglich, ein Lambda als Block zu übergeben? vielleicht zu #map? –

9

Ich vermute, das eine doppelte Frage sein kann, aber einen Wert aus einem Block zu geben, next

simple.map do |n| 
    if n%2 == 0 
    next :even 
    else 
    next :odd 
    end 
end 
+0

hm, das scheint genau das zu sein, wonach ich gesucht habe :) danke :) –

3

Kürzeste Variante Andrew Antwort verwenden mit:

simple.map { |n| next :even if n % 2 == 0; :odd } 
+1

Noch einen Schritt weiter:' simple.map {| n | nächstes n% 2 == 0? : gerade:: merkwürdig} ';-) –