2012-06-22 14 views
15

Oczywiście ||= nie zadziałaJak mogę zapamiętać metodę, która może zwrócić wartość true, false lub nil w Ruby?

def x? 
    @x_query ||= expensive_way_to_calculate_x 
end 

bo jeśli okaże się false lub nil, następnie expensive_way_to_calculate_x dostanie uruchomić kółko.

Obecnie najlepszym sposobem wiem jest umieścić wartość do w Array:

def x? 
    return @x_query.first if @x_query.is_a?(Array) 
    @x_query = [expensive_way_to_calculate_x] 
    @x_query.first 
end 

Czy jest bardziej konwencjonalny lub skuteczny sposób to zrobić?

UPDATE zdałem sobie sprawę, że chciałem memoize nil oprócz false - to idzie przez całą drogę z powrotem do https://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false-boolean-as-cached-value - moje przeprosiny do Andrew Marshall który dał się zupełnie inaczej poprawną odpowiedź.

+0

Oto, czym są 'nil' i cała koncepcja' null'. – meagar

+0

Edytowałem moje pytanie, ponieważ nie zrobiłem tego dobrze za pierwszym razem - również chcę zapamiętać zero. –

Odpowiedz

26

Jawnie sprawdzić, czy wartość @x_query jest nil zamiast:

def x? 
    @x_query = expensive_way_to_calculate_x if @x_query.nil? 
    @x_query 
end 

Należy pamiętać, że jeśli nie było to zmienna instancji, trzeba by sprawdzić, czy została zdefiniowana także/zamiast od wszystkich zmiennych instancji domyślnie nil.

Biorąc pod uwagę Twój aktualizacja, która @x_query „wartość memoized s może być nil, można użyć defined? zamiast ominąć faktu, że wszystkie zmienne instancji domyślnie nil:

def x? 
    defined?(@x_query) or @x_query = expensive_way_to_calculate_x 
    @x_query 
end 

Zauważ, że robi coś podobnego a = 42 unless defined?(a) won” t działa zgodnie z oczekiwaniami, ponieważ gdy parser trafi na a =,jest zdefiniowany jako przed osiąga warunek. Nie jest to jednak prawdą w przypadku zmiennych instancji, ponieważ domyślnie są to nil parser nie definiuje ich, gdy trafi na =. Niezależnie od tego uważam, że dobrym idiomem jest używanie długich bloków w postaci or lub unless zamiast jednolinijkowego unless z defined?, aby zachować spójność.

+0

Zamierzam upublicznić to, ponieważ jest to odpowiedź na pierwszą wersję mojego pytania, ale proszę spojrzeć na moje zmiany - ponownie, przepraszam. –

+0

@SeamusAbshere zaktualizowałem swoją odpowiedź, aby odzwierciedlić aktualizację ':)'. –

+3

'a = 42, chyba że zdefiniowano? (A)' tworzy 'a' zero, ale' @a = 42, o ile nie jest zdefiniowane? (@ A) 'tworzy' @ a' 42, więc składnia 'or' nie jest absolutnie wymagana w tym przykładzie. –

18

Aby uwzględnić nil, użyj defined? aby sprawdzić, czy zmienna została zdefiniowana:

def x? 
    return @x_query if defined? @x_query 
    @x_query = expensive_way_to_calculate_x 
end 

defined? powróci nil jeśli zmienna nie została zdefiniowana, lub ciąg "instance_variable" inaczej:

irb(main):001:0> defined? @x 
=> nil 
irb(main):002:0> @x = 3 
=> 3 
irb(main):003:0> defined? @x 
=> "instance-variable" 
Powiązane problemy