Thành ngữ ruby ​​hay nhất cho "nil or zero"


82

Tôi đang tìm kiếm một cách ngắn gọn để kiểm tra một giá trị để xem nó là 0 hay 0. Hiện tại tôi đang làm những việc như:

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

Nhưng điều này có vẻ rất vụng về.


1
Điều gì sẽ xảy ra nếu val bằng false?
Andrew Grimm

Câu trả lời:


70

Đối tượng có một con số không? phương pháp .

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

Hoặc, chỉ cho một hướng dẫn:

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

5
coi chừng việc sử dụng "hoặc" và "và", btw, chúng có mức độ ưu tiên khác nhau và rất thấp so với || và &&. Xem blog.jayfields.com/2007/08/… để biết một số nhận xét.
Mike Woodhouse 16/10/08

Tôi đồng ý với một số áp phích về "mùi" trong câu hỏi, tuy nhiên đối với tôi đây là cách của ruby ​​nhiều hơn.
Jonke

6
Mức độ ưu tiên của orkhông yêu cầu bất kỳ parens nào ở đây và sẽ đọc hoàn toàn tự nhiên cho một Rubyist có kinh nghiệm. Những người duy nhất từng bị cắn ||so với ornhững người chưa bao giờ lập trình Perl :)
ephemient 16/10/08

1
Thời gian duy nhất bạn cần lo lắng về || ưu tiên so với OR trong gán, không phải kiểm tra boolean. Tuy nhiên, mức độ ưu tiên thấp của từ này có thể rất hữu ích cho việc kiểm tra lỗi.
Robert K

3
Tôi nghĩ val && val == 0là tốt hơn.
Nakilon

35

Nếu bạn thực sự thích tên phương thức có dấu chấm hỏi ở cuối:


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

Giải pháp của bạn là tốt, cũng như một số giải pháp khác.

Ruby có thể khiến bạn tìm kiếm một cách hay để làm mọi thứ, nếu bạn không cẩn thận.


31

Từ Ruby 2.3.0 trở đi, bạn có thể kết hợp toán tử điều hướng an toàn ( &.) với Numeric#nonzero?. &.trả về nilnếu phiên bản là nilnonzero?- nếu số là 0:

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

Hoặc postfix:

do_something unless val&.nonzero?

Đây là một câu trả lời mới và hiện đại tuyệt vời. Ngoài ra, có một bài viết tuyệt vời về lý do tại sao sử dụng nó ở đây: Toán tử Điều hướng An toàn (&.) Trong Ruby
Michael Gaskill

1
Rất ngắn gọn, nhưng không có bình luận nó sẽ đưa tôi một chút thời gian để hiểu rằng unless val&.nonzero?dịch để "nếu val là con số không hoặc không có"
Stefan

1
@Stefan, đã đồng ý. Bản thân tôi sẽ không sử dụng điều này trong mã sản xuất. Tôi bao gồm nó cho chủ nghĩa bổ sung. Điều ngược lại hoàn toàn có thể đọc được - do_something if val&.nonzero?(hay còn gọi là nếu valkhông nilvà không phải bằng không).
ndnenkov

29

Trước hết, tôi nghĩ đó là cách ngắn gọn nhất mà bạn có thể kiểm tra tình trạng cụ thể đó.

Thứ hai, đối với tôi đây là mùi mã cho thấy một lỗ hổng tiềm ẩn trong thiết kế của bạn. Nói chung nil và 0 không có nghĩa giống nhau. Nếu có thể, bạn nên cố gắng loại bỏ khả năng val là nil trước khi bạn nhấn mã này, bằng cách kiểm tra điều đó ở đầu phương pháp hoặc một số cơ chế khác.

Bạn có thể có một lý do hoàn toàn chính đáng để làm điều này, trong trường hợp này, tôi nghĩ mã của bạn tốt, nhưng ít nhất tôi sẽ cân nhắc việc cố gắng loại bỏ kiểm tra nil nếu có thể.


4
Rất đúng về mùi mã! 1 Có thể xem xét nhìn vào NullObject mẫu en.wikipedia.org/wiki/Null_Object_pattern
abyx

9

Bạn có thể sử dụng Object.nil? để kiểm tra cụ thể nil (và không bị mắc kẹt giữa false và nil). Bạn cũng có thể vá một phương thức vào 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

Điều này không được khuyến nghị vì các thay đổi đối với Đối tượng rất khó để đồng nghiệp theo dõi và có thể khiến mã của bạn không thể đoán trước được đối với người khác.


Tôi sẽ sửa đổi lớp Numeric hơn là Đối tượng.
epochwolf

6
epochwolf, nếu bạn đặt điều này trên lớp Numeric, thì nil?sẽ luôn trả về false. nil?chỉ trả về true trên NilClass.
Ryan McGeary

Bạn có thể thực hiện các phương pháp trong Object, NilClassNumeric. Objectsẽ trở lại false, NilClasssẽ trở lại trueNumericsẽ trở lại zero?.
Stefan

6

nil.to_i trả về số không, vì vậy tôi thường làm điều này:

val.to_i.zero?

Tuy nhiên, bạn sẽ có một ngoại lệ nếu val là một đối tượng không phản hồi_to #to_i.


để tham khảo: Câu trả lời của Scott và @AndrewGrimm nói gì về nó:"5".to_i == 5, but you're more or less right. Clever but doesn't actually work
Paul van Leeuwen

4

Tôi tin rằng mã của bạn không chính xác; nó sẽ trong thử nghiệm thực tế cho ba giá trị: nil, false, và zero. Điều này là do !valbiểu thức đúng với tất cả các giá trị sai, trong Ruby là nilfalse.

Điều tốt nhất tôi có thể nghĩ ra ngay bây giờ là

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

Tất nhiên là không thông minh lắm, nhưng (rất) rõ ràng.


bạn có thể giả định rằng biến được đề cập là một Số. Nếu bạn thậm chí không biết đó là Boolean hay Numeric thì có những vấn đề lớn hơn trong mã.
Mike Deck

Tôi muốn sử dụng .nil? not == nil
RichH 16/10/08

4

Giải pháp của tôi cũng sử dụng Refinements, trừ đi các điều kiện.

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 thực hiện điều này thông qua các phương thức truy vấn thuộc tính, trong đó ngoài false và nil, 0 và "" cũng đánh giá thành false.

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

Tuy nhiên nó có phần của những lời gièm pha. http://www.joegrossberg.com/archives/002995.html


Liên kết không hoạt động. Tôi tò mò về phương pháp #attribute, vì tôi không thể tìm thấy bất cứ điều gì giống như vậy.
mrzasa

Nó là thứ mà Rails / ActiveRecord bổ sung khi đang bay. Nếu Khách hàng có trường tên, tên? được tự động thêm vào để kiểm tra xem tên có trống hay không. Xem api.rubyonrails.org/classes/ActiveRecord/Base.html - tìm kiếm phần 'phương pháp truy vấn thuộc tính'
Gishu

2

Để trở nên thành ngữ nhất có thể, tôi đề nghị điều này.

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

Bởi vì:

  • Nó sử dụng con số không? phương pháp.
  • Nó sử dụng toán tử "hoặc", thích hợp hơn là ||.
  • Nó không sử dụng dấu ngoặc đơn, điều này không cần thiết trong trường hợp này. Dấu ngoặc chỉ nên được sử dụng khi chúng phục vụ một số mục đích, chẳng hạn như ghi đè mức độ ưu tiên của các toán tử nhất định.

1
Mặc dù tôi biết điều này là từ nghĩa đen 7 năm trước, tôi downvoted vì điều này: github.com/bbatsov/ruby-style-guide#no-and-or-or
Devon Parsons

2

Ngắn gọn và rõ ràng

[0, nil].include?(val)


2
Cũng có thể đảo ngược điều đó:val.in? [0,nil]
mahemoff

1
@mahemoff đó chắc chắn là thành ngữ hay nhất cho nó!
intmarinoreturn0

@mahemoff sử dụng tốt hơn bao gồm ?, vì nó nhanh hơn in? ref: stackoverflow.com/questions/28272550/…
Lakhani Aliraza

Tốt, nhưng tôi đã chạy nó ngay bây giờ trên Ruby hiện đại và trong? thực sự nhanh hơn đối với một lệnh gọi duy nhất và đối với 1000 lệnh gọi, chúng khá giống nhau. Cả hai đều nhanh như chớp, đủ để một số ứng dụng bị ảnh hưởng imo. gist.github.com/mahemoff/7232648e1ccb9d23e0f4670913400bd8
mahemoff

2

Cách ngắn nhất và tốt nhất nên là

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

Đối với val&.>(0) nó trả về nil khi val là nil vì> về cơ bản cũng là một phương thức, nil bằng false trong ruby. Nó trả về false khi val == 0.


3
Ngắn nhất cái gì ?, cách tốt nhất hơn cái gì?
Sebastian Palma

0

Tôi giải quyết vấn đề này bằng cách xác định "là?" mà sau đó tôi có thể triển khai khác nhau trên các lớp khác nhau. Vì vậy, đối với Array, "là?" có nghĩa là "kích thước> 0"; đối với Fixnum nó có nghĩa là "self! = 0"; đối với String, nó có nghĩa là "self! = ''". NilClass, tất nhiên, định nghĩa "là?" như chỉ trả về con số không.


0

Bạn có thể sử dụng casenếu bạn thích:

 case val with nil, 0
      # do stuff
 end

Sau đó, bạn có thể sử dụng bất cứ thứ gì phù hợp với nó ===, đôi khi điều này rất hay. Hoặc làm điều gì đó như sau:

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ó không hẳn là OOP tốt, nhưng nó rất linh hoạt và hoạt động. Của tôi ifthường kết thúc là cases dù sao.

Tất nhiên Enum.any?/ Enum.include?loại công việc quá ... nếu bạn muốn thực sự khó hiểu:

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

Tất nhiên, điều đúng đắn cần làm là xác định một phương thức hoặc hàm. Hoặc, nếu bạn phải làm điều tương tự với nhiều giá trị, hãy sử dụng kết hợp các trình vòng lặp tốt đẹp đó.


0

Tôi thực sự thích Rails blank?phương pháp cho rằng loại của sự vật, nhưng nó sẽ không trở về truecho 0. Vì vậy, bạn có thể thêm phương pháp của mình:

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

Và nó sẽ kiểm tra xem một số giá trị là 0 hay 0:

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

if val.nil_zero?
  #...
end

0

Thay vì chắp vá một lớp, bạn có thể sử dụng các sàng lọc bắt đầu từ Ruby 2.1. Việc sàng lọc tương tự như việc vá khỉ; trong đó, chúng cho phép bạn sửa đổi lớp, nhưng việc sửa đổi bị giới hạn trong phạm vi bạn muốn sử dụng nó.

Điều này là quá mức cần thiết nếu bạn muốn thực hiện việc kiểm tra này một lần, nhưng nếu bạn đang lặp lại chính mình thì đó là một sự thay thế tuyệt vời cho việc vá khỉ.

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

Các sàng lọc đã được thay đổi vào phút cuối để được đưa vào phạm vi tệp. Vì vậy, các ví dụ trước đó có thể đã cho thấy điều này, điều này sẽ không hoạt động.

class Car
  using NilOrZero
end

0

Điều này rất ngắn gọn:

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

Nó hoạt động miễn là bạn không ngại đối xử falsegiống như nil. Trong các dự án tôi đã làm việc, sự khác biệt đó chỉ quan trọng đôi khi. Phần còn lại của thời gian cá nhân tôi thích bỏ qua .nil?và có mã ngắn hơn một chút.

[ Cập nhật : Tôi không viết những thứ như thế này nữa. Nó hoạt động nhưng quá khó hiểu. Tôi đã cố gắng giải quyết những sai lầm của mình bằng cách thay đổi một vài chỗ mà tôi đã làm.]

Nhân tiện, tôi đã không sử dụng .zero?vì điều này tạo ra một ngoại lệ nếu vallà một chuỗi. Nhưng .zero?sẽ ổn nếu bạn biết không phải như vậy.


[edited]Tôi nghĩ rằng nếu vallà nil thì biểu thức này sẽ đánh giá thành nil == 0(và do đó trả về false). Tuy nhiên, có vẻ như nó thực sự hoạt động, mặc dù tôi không nghĩ rằng nó rất dễ đọc.
omnikron

Bây giờ tôi tin rằng cách tiếp cận của tôi ở đây quá khó hiểu, chỉ để lưu một vài ký tự, và tôi sẽ không viết nó như thế này ngày nay. Vì vậy, tôi không mong đợi bất kỳ upvotes, nhưng tôi là một chút ngạc nhiên khi thấy downvotes cho một câu trả lời làm việc (mặc dù nó là hương vị không rõ ràng) ...
antinome

0

Điều này đánh giá là true cho nil và zero: nil.to_s.to_d == 0



-1

Giải pháp khác:

if val.to_i == 0
  # do stuff
end

1
Điều này chỉ hoạt động nếu val là số nguyên hoặc nil; 0,5.to_i == 0, any_string.to_i == 0, v.v.
Zach Langley

"5".to_i == 5, nhưng bạn ít nhiều đúng. Thông minh nhưng không thực sự hiệu quả.
Andrew Grimm

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

3
-1: Nếu giá trị trong valcần được giữ lại thì sao? Bạn đang chặn dữ liệu đầu vào bằng phương pháp này và có những cách tốt hơn, ít phá hoại hơn để kiểm tra nil hay 0.
Platinum Azure

3
Còn nếu (val || 0) .zero thì sao?
timkay
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.