"nil or zero"를위한 ​​최고의 루비 관용구


82

값이 nil인지 0인지 확인하는 간결한 방법을 찾고 있습니다. 현재 나는 다음과 같은 일을하고있다.

if (!val || val == 0)
  # Is nil or zero
end

그러나 이것은 매우 서투른 것 같습니다.


1
val이 같으면 false어떻게됩니까?
Andrew Grimm

답변:


70

객체에 nil이 있습니까? 방법 .

if val.nil? || val == 0
  [do something]
end

또는 단 하나의 지침에 대해 :

[do something] if val.nil? || val == 0

5
"or"와 "and"의 사용을 조심하세요, btw, 그들은 ||에 비해 다르고 매우 낮은 우선 순위를 가지고 있습니다 || 및 &&. 몇 가지 설명 은 blog.jayfields.com/2007/08/… 을 참조하십시오 .
Mike Woodhouse

나는 질문의 "냄새"에 대한 포스터에 동의하지만 나에게는 이것이 루비 방식에 가깝다.
Jonke

6
의 우선 순위는 or여기에 괄호가 필요하지 않으며 숙련 된 Rubyist에게 완전히 자연스럽게 읽힐 것입니다. ||대에 물린 유일한 사람은 orPerl을 프로그래밍 한 적이없는 사람입니다. :)
ephemient

1
걱정해야 할 유일한 시간 || 대 OR 우선 순위는 부울 검사가 아닌 할당에 있습니다. 그러나 단어의 낮은 우선 순위는 오류 검사에 매우 유용 할 수 있습니다.
Robert K

3
val && val == 0더 낫다고 생각 합니다.
Nakilon

35

끝에 물음표가있는 메서드 이름을 정말 좋아한다면 :


if val.nil? || val.zero?
  # do stuff
end

귀하의 솔루션은 다른 몇 가지 솔루션과 마찬가지로 괜찮습니다.

루비는 조심하지 않으면 모든 것을 할 수있는 예쁜 방법을 찾게 만들 수 있습니다.


31

Ruby 2.3.0부터는 안전한 탐색 연산자 ( &.)를 Numeric#nonzero?. 인스턴스가 다음 과 같고-숫자가 다음 과 같으면 &.반환 nil합니다 .nilnonzero?0

unless val&.nonzero?
  # Is nil or zero
end

또는 접미사 :

do_something unless val&.nonzero?

이것은 훌륭하고 새롭고 현대적인 대답이었습니다. 또한 여기에 사용하는 이유에 대한 훌륭한 기사가 있습니다. Ruby의 Safe Navigation Operator (&.)
Michael Gaskill

1
매우 간결하지만, 코멘트를하지 않고는 이해하기 위해 나에게 시간이 걸릴 것 unless val&.nonzero?"만약 발 IS 전무 제로"로 변환을
스테판

1
@ 스테판, 동의했습니다. 나는 이것을 프로덕션 코드에서 직접 사용하지 않을 것입니다. 완성주의를 위해 포함 시켰습니다. 반대 완벽하게 읽을 생각입니다 - do_something if val&.nonzero?(일명 경우 val하지 nil가 아닌 영).
ndnenkov

29

먼저 그 특정 상태를 확인할 수있는 가장 간결한 방법이라고 생각합니다.

둘째, 이것은 디자인의 잠재적 인 결함을 나타내는 코드 냄새입니다. 일반적으로 nil과 0은 같은 것을 의미해서는 안됩니다. 가능하다면 메서드의 시작 부분이나 다른 메커니즘을 확인하여이 코드를 누르기 전에 val이 nil 일 가능성을 제거해야합니다.

이 경우 코드가 좋다고 생각하는 완벽하게 합법적 인 이유가있을 수 있지만 적어도 가능하면 nil 검사를 제거하는 것을 고려할 것입니다.


4
코드 냄새에 대해 아주 맞습니다! +1 NullObject 패턴 en.wikipedia.org/wiki/Null_Object_pattern
abyx 2009

9

Object.nil을 사용할 수 있습니까? 구체적으로 nil을 테스트하기 위해 (그리고 false와 nil 사이에 걸리지 않습니다). 메서드를 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

Object에 대한 변경 사항은 동료가 추적하기 어렵고 다른 사람이 코드를 예측할 수 없게 만들 수 있으므로 권장되지 않습니다.


Object 대신 Numeric 클래스를 수정합니다.
epochwolf

6
epochwolf, 이것을 Numeric 클래스에 넣으면 nil?항상 false를 반환합니다. nil?NilClass에서만 true를 반환합니다.
Ryan McGeary

Object, NilClass및 에서 메서드를 구현할 수 Numeric있습니다. Object반환하고 false, NilClass반환 true하고 Numeric반환 zero?합니다.
Stefan

6

nil.to_i는 0을 반환하므로 자주 이렇게합니다.

val.to_i.zero?

그러나 val이 #to_i에 응답하지 않는 객체이면 예외가 발생합니다.


참고로 : Scott의 대답 과 @AndrewGrimm이 그것에 대해 말한 것 :"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
Paul van Leeuwen

4

귀하의 코드가 잘못되었다고 생각합니다. : 그것은 사실 시험에서 세 가지 값에 대한 것 nil, false및 0. 이는 !val루비에서 nil및 인 거짓 인 모든 값에 대해 표현식이 참 이기 때문 false입니다.

내가 지금 생각 해낼 수있는 최선의 방법은

if val == nil || val == 0
  # do stuff
end

물론 영리하지는 않지만 (매우) 명확합니다.


문제의 변수가 숫자라고 가정 할 수 있습니다. 부울인지 숫자인지조차 모르는 경우 코드에 더 큰 문제가 있습니다.
Mike Deck

.nil을 사용할까요? not == nil
RichH

4

내 솔루션은 조건을 제외한 구체화도 사용합니다.

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

2

Rails는 속성 쿼리 메서드를 통해이를 수행합니다. 여기서 false 및 nil 외에도 0 및 ""도 false로 평가됩니다.

if (model.attribute?) # => false if attribute is 0 and model is an ActiveRecord::Base derivation

그러나 그것은 비방하는 사람들의 몫이 있습니다. http://www.joegrossberg.com/archives/002995.html


링크가 작동하지 않습니다. 나는 방법에 대해 궁금합니다 #attribute. 왜냐하면 나는 그런 것을 찾을 수 없기 때문입니다.
mrzasa

Rails / ActiveRecord가 즉석에서 추가하는 것입니다. 고객에게 이름 필드가있는 경우 이름? 이름이 비어 있는지 또는 nil인지 확인하기 위해 자동으로 추가됩니다. 참조 api.rubyonrails.org/classes/ActiveRecord/Base.html - '속성 쿼리 방법'섹션 검색
Gishu

2

가능한 한 관용적이기 위해 이것을 제안합니다.

if val.nil? or val == 0
    # Do something
end

때문에:

  • nil을 사용합니까? 방법.
  • ||보다 선호되는 "or"연산자를 사용합니다.
  • 이 경우에는 필요하지 않은 괄호를 사용하지 않습니다. 괄호는 특정 연산자의 우선 순위를 재정의하는 것과 같은 특정 용도에 사용되는 경우에만 사용해야합니다.

1
나는이 말 그대로 칠년 전부터 알고 있지만, 나는이 때문에을 downvoted : github.com/bbatsov/ruby-style-guide#no-and-or-or
데본 파슨스

2

짧고 명확

[0, nil].include?(val)


2
역으로도 가능합니다 :val.in? [0,nil]
mahemoff

1
@mahemoff는 확실히 최고의 관용구입니다!
intmarinoreturn0

@mahemoff 더 나은 사용은?, 그것보다 빠르기 때문에? REF : stackoverflow.com/questions/28272550/...
카니 Aliraza

좋은 지적이지만 지금 막 현대 Ruby에서 실행 했습니까? 실제로 단일 호출의 경우 더 빠르며 1000 호출의 경우 매우 유사합니다. 어쨌든 둘 다 엄청나게 빠르기 때문에 imo에 영향을 미치는 응용 프로그램이 거의 없습니다. gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400bd8
mahemoff

2

가장 짧고 가장 좋은 방법은

if val&.>(0)
  # do something
end

들어 val&.>(0) 이 때 발 IS 전무 이후 nil을 반환> 기본적으로 루비에서 false로 동일 전무, 또한 방법이다. 이 때 false를 돌려줍니다 val == 0.


3
무엇보다 최단?, 무엇보다 가장 좋은 방법?
Sebastian Palma

0

"is?"를 정의하여이를 처리합니다. 메서드를 사용하면 다양한 클래스에서 다르게 구현할 수 있습니다. 그래서 Array의 경우 "is?" 의미 "크기> 0"; Fixnum의 경우 "self! = 0"을 의미합니다. String의 경우 "self! = ''"를 의미합니다. 물론 NilClass는 "is?"를 정의합니다. nil을 반환합니다.


0

원하는 case경우 사용할 수 있습니다 .

 case val with nil, 0
      # do stuff
 end

그런 다음에서 작동하는 모든 것을 사용할 수 있습니다 ===. 또는 다음과 같이하십시오.

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

정확히 좋은 OOP는 아니지만 매우 유연하고 작동합니다. 어쨌든 내 ifs는 보통 s로 끝납니다 case.

물론 Enum.any?/ Enum.include?종류의 작품도 ... 정말 비밀스러워지고 싶다면 :

if [0, nil].include? val
    #do stuff
end

당연히 방법이나 기능을 정의하는 것이 옳은 일입니다. 또는 많은 값으로 동일한 작업을 수행해야하는 경우 이러한 멋진 반복기 조합을 사용하십시오.


0

정말 레일과 같은 I blank?가지의 종류의 방법,하지만 반환하지 않습니다 true에 대한 0. 따라서 방법을 추가 할 수 있습니다.

def nil_zero? 
  if respond_to?(:zero?) 
    zero? 
  else 
    !self 
  end 
end 

그리고 어떤 값이 nil 또는 0인지 확인합니다.

nil.nil_zero?
=> true
0.nil_zero?
=> true
10.nil_zero?
=> false

if val.nil_zero?
  #...
end

0

원숭이가 클래스를 패치하는 대신 Ruby 2.1부터 개선을 사용할 수 있습니다 . 개선은 원숭이 패치와 유사합니다. 즉, 클래스를 수정할 수 있지만 수정은 사용하려는 범위로 제한됩니다.

이 검사를 한 번 수행하려면 과잉이지만 반복하는 경우 원숭이 패치에 대한 훌륭한 대안입니다.

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

파일 범위를 지정하기 위해 마지막 순간에 수정 사항이 변경되었습니다 . 따라서 이전 예제에서 이것을 보여줄 수 있지만 작동하지 않습니다.

class Car
  using NilOrZero
end

0

이것은 매우 간결합니다.

if (val || 0) == 0
  # Is nil, false, or zero.
end

그것은만큼 당신이 치료 괜찮다로 작동 false과 동일 nil. 내가 작업 한 프로젝트에서 그 구별은 가끔 중요합니다. 나머지 시간에는 개인적으로 건너 뛰고 .nil?코드가 약간 짧아지는 것을 선호 합니다.

[ 업데이트 : 더 이상 이런 건 쓰지 않아요. 작동하지만 너무 애매합니다. 내가 한 몇 군데를 바꿔서 내 잘못을 바로 잡으려고 노력했다.]

그건 그렇고, 예를 들어 문자열 .zero?이면 예외 val가 발생 하기 때문에 사용하지 않았습니다 . 그러나 .zero?그것이 사실이 아니라는 것을 알고 있다면 괜찮을 것입니다.


[edited]나는 만약 valnil이면이 표현식이 다음 nil == 0과 같이 평가 될 것이라고 생각했다 false. 그러나 실제로는 작동하는 것처럼 보이지만 읽기가 쉽지는 않습니다.
omnikron

나는 지금 여기에서의 나의 접근이 문자 몇 개를 저장하기에는 너무 모호하다고 생각하며 요즘에는 이렇게 쓰지 않을 것입니다. 그래서 나는 어떤 찬성도 기대하지 않지만, 작동하는 답변에 대한
반대표에

0

이것은 nil과 0에 대해 true로 평가됩니다. nil.to_s.to_d == 0



-1

또 다른 해결책 :

if val.to_i == 0
  # do stuff
end

1
이것은 val이 정수 또는 nil 인 경우에만 작동합니다. 0.5.to_i == 0, any_string.to_i == 0 등
Zach Langley

"5".to_i == 5, 그러나 당신은 다소 옳습니다. 영리하지만 실제로 작동하지 않습니다.
Andrew Grimm

-3
val ||= 0
if val == 0
# do something here
end

3
-1 : 값을 val유지해야하는 경우 어떻게 합니까? 이 방법으로 입력 데이터를 막고 있으며 nil 또는 0을 확인하는 더 좋고 덜 파괴적인 방법이 있습니다.
Platinum Azure

3
if (val || 0) .zero는 어떻습니까?
timkay
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.