Có một Ruby, hoặc Ruby-ism cho not_nil không? đối lập với nil? phương pháp?


87

Tôi chưa có kinh nghiệm về Ruby, vì vậy mã của tôi cảm thấy "xấu xí" và không phải là thành ngữ:

def logged_in?
  !user.nil?
end

Tôi muốn có một cái gì đó giống như

def logged_in?
  user.not_nil?
end

Nhưng không thể tìm thấy một phương pháp đối lập như vậy nil?

Câu trả lời:


51

khi bạn đang sử dụng ActiveSupport, có user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F , để kiểm tra không phải nil, tại sao không sử dụng

def logged_in?
  user # or !!user if you really want boolean's
end

48
Lưu ý: present?yêu cầu một chuỗi không trống. ! "".nil?trả về true, nhưng "".present?trả về false.
lambshaanxy

9
Lưu ý 2: Tôi cũng sẽ lưu ý rằng !! người dùng KHÔNG phân biệt giữa người dùng là nil và người dùng là false; việc sử dụng hai tiếng nổ kết hợp hai điều đó. Vì vậy, nếu bạn thực sự muốn xác định xem một đối tượng không phải là nil (nghĩa là: true, false, 0, "", bất kỳ thứ gì khác ngoài nil), bạn cần sử dụng phương pháp 'xấu xí' mà berkes không thích hoặc Monkeypatch mà @Tempus đề xuất bên dưới . Tất nhiên trong trường hợp này không cần đến nil (người dùng trong Rails), cách tiếp cận mà Samo thực hiện là ít xấu xí nhất, imo.
likethesky

12
false.present? == false !false.nil? == true
Dudo

3
Câu trả lời này hoàn toàn không trả lời câu hỏi được hỏi. Đó là một câu trả lời cho vấn đề triển khai cụ thể này.
Ekkstein

3
Câu trả lời này không đúng. false.nil? là false, trong khi false.present? CŨNG là sai!
Mike

49

Bạn có vẻ quá quan tâm đến boolean.

def logged_in?
  user
end

Nếu người dùng là nil, thì logged_in? sẽ trả về giá trị "falsey". Nếu không, nó sẽ trả về một đối tượng. Trong Ruby, chúng ta không cần trả về true hoặc false, vì chúng ta có các giá trị "true" và "falsey" như trong JavaScript.

Cập nhật

Nếu bạn đang sử dụng Rails, bạn có thể làm cho nó dễ đọc hơn bằng cách sử dụng present?phương pháp:

def logged_in?
  user.present?
end

1
Kỳ vọng với một phương thức kết thúc bằng a ?là nó sẽ trả về một boolean. !!valuelà cách cổ điển để chuyển đổi bất kỳ thứ gì thành boolean. Không hoàn toàn giống nhau, nhưng trong trường hợp này Object#present?trong RoR cũng tốt.
tokland

điều này thực sự bị phá vỡ trong Ruby 2.4 với Path! [43] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.blank? true [44] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.to_s "/ var / folder / rp / _k99k0pn0rsb4d3lm9l3dnjh0000gn / T / d20170603-96466-zk7di7" [45] (pry) # <ReactOnRcompile # >: 0> asset_path.present? false [46] (pry) # <ReactOnRails :: AssetsPrecompile>: 0> asset_path.nil? sai
justingordon

25

Hãy coi chừng những câu trả lời khác được trình bày present?như một câu trả lời cho câu hỏi của bạn.

present?là ngược lại với blank?trong đường ray.

present?kiểm tra xem có giá trị có ý nghĩa hay không. Những điều này có thể không present?kiểm tra được:

"".present? # false
"    ".present? # false
[].present? # false
false.present? # false
YourActiveRecordModel.where("false = true").present? # false

Trong khi !nil?séc cho:

!"".nil? # true
!"    ".nil? # true
![].nil? # true
!false.nil? # true
!YourActiveRecordModel.where("false = true").nil? # true

nil?kiểm tra xem một đối tượng có thực sự là nil. Bất cứ điều gì khác: một chuỗi rỗng, 0, false, bất cứ điều gì, không phải là nil.

present?là rất hữu ích, nhưng chắc chắn không phải là ngược lại nil?. Việc nhầm lẫn cả hai có thể dẫn đến những sai sót không mong muốn.

Đối với trường hợp sử dụng của bạn present?sẽ hoạt động, nhưng luôn khôn ngoan là nhận thức được sự khác biệt.


Nên được bao gồm trong câu trả lời được chấp nhận. false.blank?không giống nhưfalse.nil?
Yason

present?sẽ truy vấn cơ sở dữ liệu của bạn, nil?sẽ không, hãy cẩn thận với điều đó
Tony

17

Có thể đây có thể là một cách tiếp cận:

class Object
  def not_nil?
    !nil?
  end
end

Ý tưởng tốt. Tôi thực hiện từ điều này mà không có not_nil? bằng Ruby. Nhưng điều này không nên !self.nil?đúng hơn !nil?, hay là selfngầm hiểu?
berkes

3
Bạn không cần bản thân. Nó sẽ được ngụ ý.
Geo

Tự được ngụ ý khi đọc từ các phương thức thể hiện (hoặc trình truy cập, thực sự chỉ là các phương thức). Khi thiết lập giá trị, một biến cục bộ cho phương thức sẽ được tạo trước khi Ruby kiểm tra cá thể lớp để tìm phương thức setter có cùng tên. Quy tắc chung: nếu bạn có bộ xử lý cấp độ có tên là xxx, hãy sử dụng "self.xxx = 3" (đặt giá trị) hoặc "temp = xxx" (đọc giá trị). Sử dụng "xxx = 3" sẽ không cập nhật trình truy cập, chỉ cần tạo một biến mới trong phạm vi phương thức.
A Fader Darkly,

4

Bạn chỉ có thể sử dụng những thứ sau:

if object
  p "object exists"
else
  p "object does not exist"
end

Điều này không chỉ hoạt động đối với nil mà còn là false, v.v., vì vậy bạn nên kiểm tra xem nó có hoạt động hiệu quả trong usecase của bạn hay không.


4

Tôi có thể cung cấp !phương pháp Ruby-esque dựa trên kết quả từ nil?phương pháp này không.

def logged_in?
  user.nil?.!
end

Vì vậy, bí mật rằng RubyMine IDE sẽ gắn cờ nó là một lỗi. ;-)


2

Tôi đến với câu hỏi này để tìm một phương thức đối tượng, để tôi có thể sử dụng tốc Symbol#to_proc thay vì một khối; Tôi thấy arr.find(&:not_nil?)phần nào dễ đọc hơn arr.find { |e| !e.nil? }.

Phương pháp tôi tìm thấy là Object#itself. Trong cách sử dụng của mình, tôi muốn tìm giá trị trong một hàm băm cho khóa name, trong đó trong một số trường hợp, khóa đó vô tình được viết hoa thành Name. Một lớp lót đó như sau:

# Extract values for several possible keys 
#   and find the first non-nil one
["Name", "name"].map { |k| my_hash[k] }.find(&:itself)

Như đã lưu ý trong các câu trả lời khác , điều này sẽ thất bại một cách ngoạn mục trong trường hợp bạn đang kiểm tra boolean.


Làm thế nào là khác với my_hash.values_at("Name", "name").find?
berkes

Nó giống hệt nhau. Tôi có một số logic khác trong bản gốc mapmà tôi đã loại bỏ để đơn giản hóa trong ví dụ này, vì vậy, như đã viết ở đây, nó có thể hoán đổi cho nhau values_at. Phần quan trọng là những gì được chuyển đến find.
Ian
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.