2011-06-17 24 views
13

Khoa học đằng sau thực tế là phương thức to_i trong các cá thể NilClass của Ruby trả về số không? Trả lại nil hoặc tăng ngoại lệ sẽ không hợp lý hơn?Ruby Nil và Zero

+3

liên quan: Bạn có thể sử dụng 'n = Integer (str)' nếu bạn muốn nâng cao một ngoại lệ trên thất bại. – Dogbert

Trả lời

12

NilClass định nghĩa #to_i với cùng lý do nó định nghĩa một #to_a trả []. Nó đem lại cho bạn một cái gì đó của đúng loại mà là một loại sản phẩm nào có giá trị.

Điều này thực sự khá hữu ích. Ví dụ:

<%= big.long.expr.nil? ? "" : big.long.expr %> 

trở thành:

<%= big.long.expr %> 

Phần lớn đẹp hơn! (Erb đang kêu gọi #to_s đó, cho con số không, là "".) Và:

if how.now.brown.cow && how.now.brown.cow[0] 
    how.now.brown.cow[0] 
else 
    0 
end 

trở thành:

how.now.brown.cow.to_a[0].to_i 

Quá trình chuyển đổi ngắn tồn tại khi chỉ có một đại diện là cần thiết. Các chuyển đổi dài là những cái mà các phương thức lõi của Ruby gọi và chúng đòi hỏi một cái gì đó rất gần. Sử dụng chúng nếu bạn muốn kiểm tra kiểu.

Đó là:

thing.to_int # only works when almost Integer already. NilClass throws NoMethodError 

thing.to_i # this works for anything that cares to define a conversion 
+0

* "Đẹp hơn nhiều!" * Vâng, điều đó phụ thuộc vào việc bạn và bất cứ ai khác làm việc trong dự án biết Ruby và bạn muốn dựa vào hành vi không trực quan đến mức nào. 'nil.to_i' trả về 0 thay vì tăng một ngoại lệ không có ý nghĩa logic. Làm thế nào bạn có thể lấy '0' từ' nil'? Nó không giống 'nil == 0' trả về true, nhưng' to_i' ngụ ý sự tương đương. –

+4

@Ed S .: Không, 'to_int' ngụ ý một sự tương đương,' to_i' là rất lỏng lẻo, nó thực sự không hàm ý gì nhiều. –

+1

câu trả lời tuyệt vời! Tôi luôn luôn bỏ qua những chuyển đổi dài, bây giờ tôi có thể hiểu họ và làm thế nào phù hợp trong triết lý của ruby. –

13

Nó phù hợp với triết lý của Ruby của dãi (như trái ngược với, ví dụ, nghiêm minh của Python):

nil.to_i #=> 0 
"".to_i #=> 0 
"123hello".to_i #=> 123 
"hello".to_i #=> 0 

Thành thật mà nói, tôi nghĩ rằng đây là quá dễ dãi. Như đã lưu ý bởi Zabba, bạn có thể sử dụng Kernel#Integer(string) để chuyển đổi nghiêm ngặt.

+3

Bạn không cần sử dụng regex. Nếu bạn muốn lỗi khi một chuỗi không hoàn toàn là một số (chẳng hạn như "123hello"), bạn có thể làm như sau: 'Integer (" 123hello ")' (ném một 'ArgumentError'). – Zabba

+0

+1 vâng, nó có vẻ quá dễ dãi. độc đáo. – Peter

6

to_i có nghĩa là "chuyển đổi tôi thành số nguyên nếu bạn có thể".

Nếu bạn muốn "nếu bạn có nhiều số nguyên như thế, hãy cho tôi giá trị số nguyên của bạn, hãy đưa ra NoMethodError", sau đó sử dụng .to_int.

Có một câu hỏi khác hỏi về sự khác biệt giữa to_ito_int, to_s so với to_str, v.v. Hãy cho tôi biết nếu bạn muốn tôi tìm nó cho bạn.

6

Giao thức của to_i nói rằng bạn phải trả về một Integer và bạn không phải huy động một ngoại lệ. Cả hai đề xuất của bạn vi phạm ít nhất một trong các quy tắc đó. Vì vậy, không, những thứ đó sẽ không chỉ không hợp lý hơn, chúng sẽ đơn giản là không hợp lệ.

Lưu ý rằng, tuy nhiên, nilkhông trả lời to_int. Nếu nó đã làm, hãy trả lời to_int, điều đó thực sự là "phi lý".

+1

Thực tế là giao thức nói rằng 'to_i' phải trả về một số nguyên không làm cho hành vi này hợp lý, nó chỉ làm cho nó phù hợp (cho sẵn, tốt hơn là tuân thủ ngay cả khi vô lý.) –

1

Nếu bạn tình cờ được trong Rails sau đó bạn có thể sử dụng try:

nil.to_i # => 0 
nil.try :to_i # => nil