Làm gì thế !! có nghĩa là trong ruby?


134

Chỉ tự hỏi những gì !!trong Ruby.

Câu trả lời:


161

Không không. Nó được sử dụng để chuyển đổi một giá trị thành boolean:

!!nil   #=> false
!!"abc" #=> true
!!false #=> false

Thông thường không cần thiết phải sử dụng vì các giá trị sai duy nhất đối với Ruby là nilfalsevì vậy, tốt nhất là để cho quy ước đó đứng vững.

Hãy nghĩ về nó như là

!(!some_val)

Một điều được sử dụng cho mục đích hợp pháp là ngăn chặn một khối dữ liệu khổng lồ được trả lại. Ví dụ: bạn có thể không muốn trả về 3 MB dữ liệu hình ảnh trong has_image?phương thức của mình hoặc bạn có thể không muốn trả về toàn bộ đối tượng người dùng của mình trong logged_in?phương thức. Sử dụng !!chuyển đổi các đối tượng này thành đơn giản true/ false.


8
Nó không phải là một thực hành xấu để sử dụng này. Double bang thường được sử dụng trong các vị từ (phương thức kết thúc bằng?) Để trả về giá trị boolean rõ ràng.
Swanand

6
Alex, bạn không thực sự cần phải lo lắng về việc trả lại các đối tượng lớn, vì Ruby sẽ trả về một tham chiếu, không phải là bản sao của đối tượng.
DSimon

10
@DSimon, đôi khi bạn cần phải lo lắng về các đối tượng lớn, như khi in hoặc ghi nhật ký một giá trị trong quá trình gỡ lỗi.
Wayne Conrad

Tại sao không trở lại .nil?thay vì sử dụng !!? Có sự khác biệt?
tro999

3
Có một sự khác biệt khi giá trị của bạn là một booelan. !!true #=> truetrue.nil? #=> false
Alex Wayne

31

Nó trả về truenếu đối tượng bên phải không nilvà không false, falsenếu nó là nilhoặcfalse

def logged_in?   
  !!@current_user
end

1
Rõ ràng là nó đến từ Restful_Auth?! : D
Cameron

14

!có nghĩa là phủ định trạng thái boolean, hai !s không có gì đặc biệt, ngoài một phủ định kép.

!true == false
# => true

Nó thường được sử dụng để buộc một phương thức trả về boolean. Nó sẽ phát hiện bất kỳ loại tính trung thực nào, chẳng hạn như chuỗi, số nguyên và những gì không, và biến nó thành một boolean.

!"wtf"
# => false

!!"wtf"
# => true

Một trường hợp sử dụng thực tế hơn:

def title
  "I return a string."
end

def title_exists?
  !!title
end

Điều này rất hữu ích khi bạn muốn chắc chắn rằng boolean được trả về. IMHO là một điều vô nghĩa, mặc dù, thấy rằng cả hai if 'some string'if truelà cùng một dòng chảy, nhưng một số người thấy hữu ích khi trả lại một cách rõ ràng một boolean.


đối với tôi, nó dường như chỉ là một cách nhanh hơn so với việc sử dụng câu lệnh if hoặc toán tử ternary. Vì bạn không thể quay lại title, cũng có thể làm điều gần gũi nhất với nó ... tôi cho rằng
Carson Myers

6

Lưu ý rằng thành ngữ này cũng tồn tại trong các ngôn ngữ lập trình khác. C không có boolkiểu nội tại , vì vậy tất cả các booleans được gõ intthay vào đó, với các giá trị chính tắc là 0hoặc 1. Lấy ví dụ này (dấu ngoặc đơn được thêm cho rõ ràng):

!(1234) == 0
!(0) == 1
!(!(1234)) == 1

Cú pháp "không phải không" chuyển đổi bất kỳ số nguyên khác không 1thành giá trị đúng boolean chính tắc.

Tuy nhiên, nói chung, tôi thấy tốt hơn nhiều khi đưa ra một so sánh hợp lý hơn là sử dụng thành ngữ không phổ biến này:

int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious

Hoặc chỉ khi (x). !! là hữu ích khi bạn cần nhận được 0/1. Bạn có thể hoặc không thể xem xét (x)? 1: 0 rõ ràng hơn.
derobert

3

Nó hữu ích nếu bạn cần làm độc quyền hoặc . Sao chép từ câu trả lời của Matt Van Horn với những sửa đổi nhỏ:

1 ^ true
TypeError: can't convert true into Integer

!!1 ^ !!true
=> false

Tôi đã sử dụng nó để đảm bảo hai biến là cả hai hoặc không hoặc không.

raise "Inconsistency" if !!a ^ !!b

3

Đó là "tiêu cực kép", nhưng thực tế đang được khuyến khích. Nếu bạn đang sử dụng rubocop , bạn sẽ thấy nó phàn nàn về mã đó với Style/DoubleNegationvi phạm.

sở lý luận nêu rõ:

Vì đây là cả mật mã và thường là dư thừa, nên tránh [sau đó diễn giải:] Thay đổi !!somethingthành!something.nil?


1
Nhưng ... !!false # => falsetrong khi!false.nil? # => true
Doug

@Doug Nếu bạn biết bạn có giá trị boolean, thì đó là dự phòng (chỉ cần sử dụng giá trị). Nếu bạn không, bạn có thể sử dụng !(foo.nil? || foo == false)- dài dòng hơn, có, nhưng ít khó hiểu hơn.
Nốt ruồi David

0

Hiểu cách thức hoạt động của nó có thể hữu ích nếu bạn cần chuyển đổi, giả sử, liệt kê thành boolean. Tôi có mã thực hiện chính xác điều đó, bằng cách sử dụng classy_enumđá quý:

class LinkStatus < ClassyEnum::Base
  def !
    return true
  end
end

class LinkStatus::No < LinkStatus
end

class LinkStatus::Claimed < LinkStatus
  def !
    return false
  end
end

class LinkStatus::Confirmed < LinkStatus
  def !
    return false
  end
end

class LinkStatus::Denied < LinkStatus
end

Sau đó, trong mã dịch vụ tôi có, ví dụ:

raise Application::Error unless !!object.link_status   # => raises exception for "No" and "Denied" states.

Thực tế, toán tử bangbang đã trở thành cái mà tôi có thể đã viết như một phương thức gọi là to_bool.

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.