Melhor linguagem Ruby para “nulo ou zero”
-
03-07-2019 - |
Pergunta
Eu estou procurando uma maneira concisa para verificar um valor para ver se ele é nulo ou zero. Atualmente estou fazendo algo como:
if (!val || val == 0)
# Is nil or zero
end
Mas isso parece muito desajeitado.
Solução
Os objetos têm um nil? método .
if val.nil? || val == 0
[do something]
end
Ou, para apenas uma instrução:
[do something] if val.nil? || val == 0
Outras dicas
Se você realmente gosta de nomes de métodos com pontos de interrogação no final:
if val.nil? || val.zero?
# do stuff
end
A sua solução é bom, como são algumas das outras soluções.
Ruby pode fazer você procurar uma maneira bonita de fazer tudo, se você não tiver cuidado.
Em primeiro lugar eu acho que é sobre a maneira mais concisa você pode verificar para essa condição particular.
Em segundo lugar, para mim este é um cheiro de código que indica uma falha potencial em seu projeto. Geralmente zero e zero não deve significar a mesma coisa. Se possível, você deve tentar eliminar a possibilidade de val ser nil antes de bater este código, quer verificando que, no início do método ou algum outro mecanismo.
Você pode ter uma razão perfeitamente legítima para fazer isso nesse caso, eu acho que o código é bom, mas eu, pelo menos, considerar a tentar livrar-se do cheque nulo, se possível.
A partir de Ruby 2.3.0 em diante, você pode combinar o operador de navegação segura (&.
) com Numeric#nonzero?
. &.
retornos nil
se a instância foi nil
e nonzero?
- se o número foi 0
:
unless val&.nonzero?
# Is nil or zero
end
Ou postfix:
do_something unless val&.nonzero?
Você pode usar o Object.nil? Para testar a nil especificamente (e não ficar preso entre falso e nil). Você pode macaco-patch um método para objetos bem.
class Object
def nil_or_zero?
return (self.nil? or self == 0)
end
end
my_object = MyClass.new
my_object.nil_or_zero?
==> false
Isto não é recomendado como alterações ao objeto são difíceis para os colegas de trabalho para rastrear e pode tornar seu código imprevisível para os outros.
Eu acredito que o código estiver incorreto; ele vai no teste de fato por três valores: nil
, false
, e zero. Isso ocorre porque a expressão !val
é verdadeiro para todos os valores que são falsas, que em Ruby é nil
e false
.
O melhor que eu posso vir acima com agora é
if val == nil || val == 0
# do stuff
end
Que, naturalmente, não é muito inteligente, mas (muito) clara.
retornos nil.to_i zero, por isso muitas vezes fazer isso:
val.to_i.zero?
No entanto, você receberá uma exceção se val é sempre um objeto que não faz respond_to #to_i.
A minha solução também usar refinamentos, menos os condicionais.
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
Rails faz isso através de métodos de consulta de atributos, onde, além de false e nil, 0 e "" também avaliam como falsa.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
No entanto, tem sua parcela de detratores. http://www.joegrossberg.com/archives/002995.html
Para ser tão idiomática quanto possível, eu sugiro isso.
if val.nil? or val == 0
# Do something
end
Porque:
- Ele usa o nulo? método.
- Ele usa o operador "ou", que é preferível ||.
- Não use parênteses, que não são necessários neste caso. Parênteses só deve ser usado quando eles servem para alguma coisa, como substituir a precedência de determinados operadores.
Shortest e melhor maneira deve ser
if val&.>(0)
# do something
end
Para val&.>(0)
ele retorna nulo quando val é nulo desde> basicamente é também um método, nada igual a falsa em ruby. Ele retornar falso quando val == 0
.
curta e clara
[0, nil].include?(val)
Eu lido com isso definindo um "é?" método, que pode, então, implementar de forma diferente em várias classes. Assim, para Array, "é?" meios "size> 0"; para Fixnum que significa "auto = 0!"; para Cordas que significa "auto! = ''". NilClass, é claro, define "é?" como apenas retornando nil.
Você pode usar case
se você gosta:
case val with nil, 0
# do stuff
end
Em seguida, você pode usar qualquer coisa que funciona com ===
, que é bom às vezes. Ou fazer algo parecido com isto:
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
Não é exatamente bom OOP, mas é muito flexível e ele funciona. Meus if
s geralmente acabam como case
s de qualquer maneira.
É claro Enum.any?
/ tipo Enum.include?
de obras também ... se você gosta de ficar muito enigmática:
if [0, nil].include? val
#do stuff
end
A coisa certa a fazer é, naturalmente, para definir um método ou função. Ou, se você tem que fazer a mesma coisa com muitos valores, use uma combinação desses iterators agradáveis.
Eu realmente gosto Rails método blank?
para esse tipo de coisas, mas não vai voltar true
para 0
. Então você pode adicionar o seu método:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
E vai verificar se algum valor é nulo ou 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Em vez de macaco remendar uma classe, você poderia usar refinamentos começando no ruby ??2.1. Refinamentos são semelhantes aos patching macaco; em que, eles permitem que você modifique a classe, mas a modificação é limitada ao âmbito você deseja usá-lo em.
Este é um exagero se você quer fazer essa verificação uma vez, mas se você está repetindo-se que é uma ótima alternativa para patching macaco.
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
refinamentos foram alteradas no último minuto para ser delimitado para o arquivo. Então exemplos anteriores podem ter mostrado isso, que não vai funcionar.
class Car
using NilOrZero
end
Isto é muito concisa:
if (val || 0) == 0
# Is nil, false, or zero.
end
Ele funciona, desde que você não se importa tratar false
o mesmo que nil
. Nos projetos em que já trabalhei, essa distinção só importa de vez em quando. O resto do tempo, eu, pessoalmente, prefiro ignorar .nil?
e têm código ligeiramente mais curto.
[ Atualizar : eu não escrever este tipo de coisa mais. Ele funciona, mas é muito enigmática. Tentei definir certas meus erros, alterando os poucos lugares onde eu fiz isso.]
A propósito, eu não usar .zero?
uma vez que este levanta uma exceção se val
é, digamos, uma string. Mas .zero?
seria bom se você sabe que não é o caso.
Isto avalia como verdadeira para zero e zero: nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
Outra solução:
if val.to_i == 0
# do stuff
end
val ||= 0
if val == 0
# do something here
end