Il miglior linguaggio rubino per "zero o zero"
-
03-07-2019 - |
Domanda
Sto cercando un modo conciso per verificare un valore per vedere se è zero o zero. Attualmente sto facendo qualcosa del tipo:
if (!val || val == 0)
# Is nil or zero
end
Ma questo sembra molto goffo.
Soluzione
Gli oggetti hanno un zero? metodo .
if val.nil? || val == 0
[do something]
end
Oppure, per una sola istruzione:
[do something] if val.nil? || val == 0
Altri suggerimenti
Se ti piacciono davvero i nomi dei metodi con punti interrogativi alla fine:
if val.nil? || val.zero?
# do stuff
end
La tua soluzione va bene, così come alcune delle altre soluzioni.
Ruby può farti cercare un modo carino di fare tutto, se non stai attento.
Prima di tutto, penso che sia il modo più conciso in cui è possibile verificare quella particolare condizione.
In secondo luogo, per me questo è un odore di codice che indica un potenziale difetto nel tuo design. Generalmente zero e zero non dovrebbero significare la stessa cosa. Se possibile, dovresti provare a eliminare la possibilità che val sia zero prima di premere questo codice, controllandolo all'inizio del metodo o in qualche altro meccanismo.
Potresti avere un motivo perfettamente legittimo per farlo, nel qual caso penso che il tuo codice sia buono, ma almeno prenderei in considerazione l'idea di provare a sbarazzarmi del controllo zero, se possibile.
Da Ruby 2.3.0 in poi, è possibile combinare l'operatore di navigazione sicura ( & amp ;.
) con Numero # diverso da zero?
. & amp ;.
restituisce zero
se l'istanza era zero
e diverso da zero?
- se il numero era 0
:
unless val&.nonzero?
# Is nil or zero
end
O postfisso:
do_something unless val&.nonzero?
Puoi usare Object.nil? per testare lo zero in modo specifico (e non farsi prendere tra false e zero). Puoi anche applicare una patch di scimmia a un metodo in 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
Questo non è raccomandato poiché le modifiche all'oggetto sono difficili da tracciare per i colleghi e possono rendere imprevedibile il tuo codice per gli altri.
Credo che il tuo codice sia errato; testerà infatti tre valori: nil
, false
e zero. Questo perché l'espressione ! Val
è vera per tutti i valori falsi, che in Ruby è zero
e false
.
Il meglio che posso inventare adesso è
if val == nil || val == 0
# do stuff
end
Che ovviamente non è molto intelligente, ma (molto) chiaro.
nil.to_i restituisce zero, quindi spesso faccio questo:
val.to_i.zero?
Tuttavia, otterrai un'eccezione se val è mai un oggetto che non risponde_ a #to_i.
La mia soluzione usa anche i perfezionamenti, meno i condizionali.
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 lo fa tramite metodi di query degli attributi, dove oltre a false e zero, 0 e " " valuta anche come falso.
if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation
Tuttavia ha la sua quota di detrattori. http://www.joegrossberg.com/archives/002995.html
Per essere il più idiomatico possibile, suggerirei questo.
if val.nil? or val == 0
# Do something
end
A causa:
- Usa lo zero? metodo.
- Utilizza " o " operatore, che è preferibile a ||.
- Non utilizza parentesi, che in questo caso non sono necessarie. Le parentesi devono essere utilizzate solo quando hanno qualche scopo, come ad esempio la precedenza di alcuni operatori.
Il modo più breve e migliore dovrebbe essere
if val&.>(0)
# do something
end
Per val & amp;. > (0)
restituisce zero quando val è zero poiché > fondamentalmente è anche un metodo, zero uguale a falso in rubino. Restituisce falso quando val == 0
.
Breve e chiaro
[0, nil] .include? (val)
Mi occupo di questo definendo un " is? " metodo, che posso quindi implementare in modo diverso su varie classi. Quindi per Array, "è?" significa "dimensione > 0"; per Fixnum significa " self! = 0 " ;; per String significa " self! = '' " ;. NilClass, ovviamente, definisce "è?" come solo tornare a zero.
Puoi usare case
se ti piace:
case val with nil, 0
# do stuff
end
Quindi puoi usare tutto ciò che funziona con ===
, il che è bello a volte. O fai qualcosa del genere:
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
Non è esattamente un buon OOP, ma è molto flessibile e funziona. Il mio if
di solito finisce comunque come case
.
Ovviamente Enum.any?
/ Enum.include?
funziona anche in qualche modo ... se ti piace diventare davvero enigmatico:
if [0, nil].include? val
#do stuff
end
La cosa giusta da fare è ovviamente definire un metodo o una funzione. Oppure, se devi fare la stessa cosa con molti valori, usa una combinazione di quei simpatici iteratori.
Mi piace molto il metodo Rails vuoto?
per quel tipo di cose, ma non restituirà true
per 0
. Quindi puoi aggiungere il tuo metodo:
def nil_zero?
if respond_to?(:zero?)
zero?
else
!self
end
end
E controllerà se un valore è zero o 0:
nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false
if val.nil_zero?
#...
end
Invece di rattoppare le scimmie in una classe, potresti usare perfezionamenti a partire da Ruby 2.1. I perfezionamenti sono simili al patching delle scimmie; in ciò, ti consentono di modificare la classe, ma la modifica è limitata all'ambito in cui desideri utilizzarla.
Questo è eccessivo se vuoi fare questo controllo una volta, ma se ti stai ripetendo è un'ottima alternativa al patching delle scimmie.
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
I perfezionamenti sono stati modificati nell'ultimo minuto per essere inclusi nel file. Quindi esempi precedenti potrebbero averlo dimostrato, il che non funzionerà.
class Car
using NilOrZero
end
Questo è molto conciso:
if (val || 0) == 0
# Is nil, false, or zero.
end
Funziona finché non ti dispiace trattare false
come nil
. Nei progetti a cui ho lavorato, questa distinzione conta solo una volta ogni tanto. Il resto del tempo preferisco personalmente saltare .nil?
e avere un codice leggermente più breve.
[ Aggiorna : non scrivo più questo genere di cose. Funziona ma è troppo criptico. Ho cercato di correggere i miei misfatti cambiando i pochi posti in cui l'ho fatto.]
A proposito, non ho usato .zero?
poiché questo solleva un'eccezione se val
è, diciamo, una stringa. Ma .zero?
andrebbe bene se sai che non è così.
Questo valore è true per zero e zero: nil.to_s.to_d == 0
unless (val || 0).zero?
# do stufff
end
Un'altra soluzione:
if val.to_i == 0
# do stuff
end
val ||= 0
if val == 0
# do something here
end