Szukam zwięzłego sposobu sprawdzenia wartości, aby sprawdzić, czy jest zerowa lub zerowa. Obecnie robię coś takiego:
if (!val || val == 0)
# Is nil or zero
end
Ale to wydaje się bardzo niezdarne.
Odpowiedzi:
Obiekty mają zero? metoda .
if val.nil? || val == 0
[do something]
end
Lub dla jednej instrukcji:
[do something] if val.nil? || val == 0
or
nie wymaga tutaj żadnych odwołań i będzie czytane całkowicie naturalnie dla doświadczonego Rubyisty. Jedynymi ludźmi, którzy kiedykolwiek zostali ugryzieni przez ||
versus, or
są ludzie, którzy nigdy nie zaprogramowali Perla :)
val && val == 0
jest lepiej.
Jeśli naprawdę lubisz nazwy metod ze znakami zapytania na końcu:
if val.nil? || val.zero?
# do stuff
end
Twoje rozwiązanie jest w porządku, podobnie jak kilka innych rozwiązań.
Ruby może sprawić, że będziesz szukał ładnego sposobu na zrobienie wszystkiego, jeśli nie będziesz ostrożny.
Począwszy od Rubiego 2.3.0, możesz łączyć bezpieczny operator nawigacji ( &.
) z Numeric#nonzero?
. &.
zwraca, nil
jeśli wystąpienie było nil
i nonzero?
- jeśli liczba to 0
:
unless val&.nonzero?
# Is nil or zero
end
Lub postfix:
do_something unless val&.nonzero?
unless val&.nonzero?
przekłada się na "jeśli val wynosi zero lub zero"
do_something if val&.nonzero?
(aka, jeśli val
nie jest nil
i nie jest zerem).
Po pierwsze, myślę, że to najbardziej zwięzły sposób na sprawdzenie tego konkretnego stanu.
Po drugie, dla mnie jest to zapach kodu, który wskazuje na potencjalną wadę twojego projektu. Generalnie zero i zero nie powinny oznaczać tego samego. Jeśli to możliwe, powinieneś spróbować wyeliminować możliwość, że val będzie zerowa, zanim trafisz na ten kod, albo sprawdzając to na początku metody, albo przez inny mechanizm.
Możesz mieć całkowicie uzasadniony powód, aby to zrobić, w takim przypadku myślę, że twój kod jest dobry, ale przynajmniej rozważę próbę pozbycia się sprawdzania zerowego, jeśli to możliwe.
Możesz użyć Object.nil? specjalnie przetestować na zero (i nie dać się złapać między fałszem a zerem). Możesz również łączyć metodę w Object.
class Object
def nil_or_zero?
return (self.nil? or self == 0)
end
end
my_object = MyClass.new
my_object.nil_or_zero?
==> false
Nie jest to zalecane, ponieważ zmiany w Object są trudne do śledzenia dla współpracowników i mogą spowodować, że Twój kod będzie nieprzewidywalny dla innych.
nil?
zawsze zwróci false. nil?
zwraca tylko wartość true w NilClass.
Object
, NilClass
i Numeric
. Object
wróci false
, NilClass
wróci true
i Numeric
wróci zero?
.
nil.to_i zwraca zero, więc często robię to:
val.to_i.zero?
Jednak otrzymasz wyjątek, jeśli val kiedykolwiek będzie obiektem, który nie odpowiada na #to_i.
"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
Uważam, że twój kod jest nieprawidłowy; to będzie w rzeczywistości badania dla trzech wartości: nil
, false
, i zero. Dzieje się tak, ponieważ !val
wyrażenie jest prawdziwe dla wszystkich wartości, które są fałszywe, czyli w Rubim nil
ifalse
.
Najlepsze, co mogę teraz wymyślić, to
if val == nil || val == 0
# do stuff
end
Co oczywiście nie jest zbyt sprytne, ale (bardzo) jasne.
Moje rozwiązanie również korzysta z zawężeń bez warunkowych.
module Nothingness
refine Numeric do
alias_method :nothing?, :zero?
end
refine NilClass do
alias_method :nothing?, :nil?
end
end
using Nothingness
if val.nothing?
# Do something
end
Railsy robią to za pomocą metod zapytań o atrybuty, gdzie oprócz wartości false i nil wartości 0 i „” również dają wartość false.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
Ma jednak swoich krytyków. http://www.joegrossberg.com/archives/002995.html
#attribute
, bo nie mogę znaleźć czegoś takiego.
Aby być tak idiomatycznym, jak to tylko możliwe, zasugerowałbym to.
if val.nil? or val == 0
# Do something
end
Dlatego:
Krótkie i jasne
[0, nil].include?(val)
val.in? [0,nil]
Powinien być najkrótszy i najlepszy sposób
if val&.>(0)
# do something
end
Ponieważ val&.>(0)
zwraca nil, gdy val jest nil, ponieważ> w zasadzie jest także metodą, nil równe jest fałszowi w ruby. Zwraca fałsz, kiedy val == 0
.
Radzę sobie z tym, definiując „jest”? metodę, którą mogę następnie wdrożyć w różny sposób na różnych klasach. Więc w przypadku tablicy „jest?” oznacza „rozmiar> 0”; dla Fixnum oznacza „self! = 0”; w przypadku String oznacza to "self! = ''". NilClass oczywiście definiuje „jest?” jako po prostu zwracając zero.
Możesz użyć, case
jeśli chcesz:
case val with nil, 0
# do stuff
end
Wtedy możesz użyć wszystkiego, co działa ===
, co czasami jest miłe. Lub zrób coś takiego:
not_valid = nil, 0
case val1 with *not_valid
# do stuff
end
#do other stuff
case val2 with *not_valid, false #Test for values that is nil, 0 or false
# do other other stuff
end
To nie jest do końca dobre OOP, ale jest bardzo elastyczne i działa. Moje if
i tak zwykle kończą się jako case
s.
Oczywiście Enum.any?
/ Enum.include?
rodzaj też działa ... jeśli lubisz być naprawdę tajemniczy:
if [0, nil].include? val
#do stuff
end
Oczywiście należy zdefiniować metodę lub funkcję. Lub, jeśli musisz zrobić to samo z wieloma wartościami, użyj kombinacji tych ładnych iteratorów.
Naprawdę podoba mi się blank?
metoda Railsów do tego typu rzeczy, ale nie wróci true
do tego 0
. Możesz więc dodać swoją metodę:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
I sprawdzi, czy jakaś wartość jest zerowa czy 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Zamiast małpy łatać klasę, możesz użyć udoskonaleń począwszy od Rubiego 2.1. Udoskonalenia są podobne do poprawiania małp; w związku z tym umożliwiają modyfikowanie klasy, ale modyfikacja jest ograniczona do zakresu, w którym chcesz jej użyć.
To przesada, jeśli chcesz raz to sprawdzić, ale jeśli się powtarzasz, jest to świetna alternatywa dla małpiego łatania.
module NilOrZero
refine Object do
def nil_or_zero?
nil? or zero?
end
end
end
using NilOrZero
class Car
def initialize(speed: 100)
puts speed.nil_or_zero?
end
end
car = Car.new # false
car = Car.new(speed: nil) # true
car = Car.new(speed: 0) # true
Doprecyzowania zostały zmienione w ostatniej chwili, aby uzyskać zakres pliku. Więc wcześniejsze przykłady mogły to pokazać, co nie zadziała.
class Car
using NilOrZero
end
To jest bardzo zwięzłe:
if (val || 0) == 0
# Is nil, false, or zero.
end
Działa tak długo, jak nie masz nic przeciwko traktowaniu false
tego samego nil
. W projektach, nad którymi pracowałem, to rozróżnienie ma znaczenie tylko raz na jakiś czas. Przez resztę czasu osobiście wolę przeskakiwać .nil?
i mieć nieco krótszy kod.
[ Aktualizacja : nie piszę już tego typu rzeczy. Działa, ale jest zbyt tajemniczy. Próbowałem naprawić swoje złe uczynki, zmieniając kilka miejsc, w których to zrobiłem.]
Nawiasem mówiąc, nie użyłem, .zero?
ponieważ powoduje to wyjątek, jeśli val
jest, powiedzmy, ciągiem. Ale .zero?
byłoby dobrze, gdybyś wiedział, że tak nie jest.
[edited]
Pomyślałem, że jeśli val
jest nil, to wyrażenie zwróci wartość nil == 0
(i zwróci false
). Wygląda jednak na to, że faktycznie działa, chociaż nie sądzę, aby był bardzo czytelny.
Inne rozwiązanie:
if val.to_i == 0
# do stuff
end
"5".to_i == 5
, ale masz mniej więcej rację. Sprytne, ale tak naprawdę nie działa.
val ||= 0
if val == 0
# do something here
end
val
trzeba zachować wartość w ? Tą metodą przebijasz dane wejściowe i istnieją lepsze, mniej destrukcyjne sposoby sprawdzania, czy nie ma zera lub zera.
false
?