2011-06-15 5 views
15

Ho un metodo di puzzolente come:Ruby "ritorno a meno che zero" idioma

def search_record(*args)  
    record = expensive_operation_1(foo) 
    return record unless record.nil? 

    record = expensive_operation_2(foo, bar) 
    return record unless record.nil? 

    record = expensive_operation_3(baz) 
    return record unless record.nil? 

    record = expensive_operation_4(foo, baz) 
    return record unless record.nil? 
end 

C'è un buon linguaggio rubino per "risultato ritorno della chiamata a meno che zero"?

Oppure devo semplicemente scrivere un metodo return_unless_nil(&blk)?

(Si noti che args sono diversi per ogni chiamata, quindi non posso semplicemente scorrere su di loro)

+0

possibile registrare essere 'false', oppure è sicuramente sia un vero e proprio record o nulla? –

+0

"O dovrei semplicemente scrivere un metodo' return_unless_nil (& blk) '?" Quale sarebbe tornato dal metodo che lo ha invocato? Non penso sia possibile. –

+0

Ho circa 10 minuti di apprendimento rubino sotto la cintura, ma sono curioso come scriveresti un metodo per possibilmente restituire un valore per il chiamante? Per quanto riguarda una potenziale risposta, mi sento a disagio nel metterla come una risposta reale data la mia esposizione molto limitata di rubini ... puoi avere qualcosa di simile in rubino? 'return (record = expensive_op (foo)) a meno record.nil?' Non sono sicuro che sia meno puzzolente per te .. –

risposta

20

Non vi preoccupate circa la differenza tra nil e false qui? Se vi interessa solo se il valore di ritorno di ogni metodo è "falsy", allora questo è un modo piuttosto Rubyish di farlo:

def search_record(*args)  
    expensive_operation_1(foo)  || 
    expensive_operation_2(foo, bar) || 
    expensive_operation_3(baz)  || 
    expensive_operation_4(foo, baz) 
end 

Se si ha familiarità con questo idioma, si può spiegare così: Rubino , come la maggior parte delle lingue, "short circuits" o confronti, il che significa che se il primo operando restituisce "truey" non si preoccupa di valutare il secondo operando (cioè se expensive_operation_1 restituisce qualcosa di diverso nil o false, non sarà mai chiamata expensive_operation_2) , perché sa già che il risultato dell'operazione booleana è vero.

Un'altra cosa utile che fa Ruby è, invece di restituire true o false da operazioni booleane, restituisce solo l'ultimo operando che valuta. Quindi in questo caso se expensive_operation_1 restituisce nil, chiamerà quindi expensive_operation_2 e se restituisce un valore (che non è falsy), l'intera espressione valuterà solo quel valore.

Infine, possiamo collegare questi booleani cosicché, in effetti, restituirà il risultato del primo operando che non è falsato e non valuterà mai gli operandi successivi. Se tutti gli degli operandi vengono valutati in modo errato, restituirà l'operando finale (che sappiamo essere falsi e, nel tuo caso, probabilmente nil).

+0

Per espandere la risposta piuttosto concisa di Jordan: Gli operatori booleani cortocircuitano (valutano solo il lato sinistro se il lato destro non è necessario) e restituiscono il valore che soddisfa l'operatore. – Chuck

+0

Grazie Chuck. Ero occupato ad ampliare la mia risposta quando hai commentato. :) –

+0

L'avvertenza "ti interessa la differenza tra nil e falso" è davvero importante. Se una di queste funzioni restituisce un valore booleano, questo codice non funzionerà. Sfortunatamente l'OP è diventato AWOL. – tokland

2

A complemento della risposta di Jordan: immaginiamo che queste funzioni possano restituire un valore booleano (improbabile per una funzione di ricerca, ma comunque) e || non funziona. Si potrebbe quindi utilizzare l'astrazione discusso here:

expensive_operation_1(foo).or_if(:nil?) do 
    expensive_operation_2(foo).or_if(:nil?) do 
    expensive_operation_3(foo).or_if(:nil?) do 
     expensive_operation_4(foo) 
    end 
    end 
end 
+0

Object # or_if è un idioma interessante da tenere a mente. Grazie! – pithyless