2011-06-17 11 views
13

Co jest nauką kryjącą się za tym, że metoda to_i w instancjach Rubin's NilClass zwraca zero? Wracając zero lub zgłaszanie wyjątku nie byłoby bardziej logiczne?Rubinowy zer i zero

+3

powiązanymi: Można użyć 'n = Integer (str)' jeśli chcesz podnieść wyjątek na niepowodzenie. – Dogbert

Odpowiedz

12

NilClass definiuje #to_i z tego samego powodu, że definiuje #to_a która zwraca []. To daje coś odpowiedniego typu, ale pustym rodzaju wartości.

Jest to całkiem przydatne. Na przykład:

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

staje:

<%= big.long.expr %> 

wiele ładniejszy! (Erb dzwoni #to_s które na zero, to ""). A:

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

staje:

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

Krótkie konwersje istnieć, gdy potrzebna jest tylko reprezentacją. Długie konwersje są tymi, które wywołują podstawowe metody Ruby i wymagają czegoś bardzo bliskiego. Użyj ich, jeśli chcesz sprawdzić typ.

Czyli:

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

* "O wiele ładniej!" Tak, to zależy od tego, jak dobrze ty i ktokolwiek pracujący przy projekcie znają Ruby i jak bardzo chcesz polegać na nieintuicyjnym zachowaniu. 'nil.to_i' zwracające 0 zamiast zgłaszania wyjątku nie logicznie logicznie. Jak uzyskać '0' z' nil'? To nie jest tak, że 'nil == 0' zwraca true, ale' to_i' oznacza równoważność. –

+4

@Ed S .: Nie, 'to_int' sugeruje równoważność,' to_i' jest tak niedbałe, że naprawdę nie implikuje wiele z niczego. –

+1

świetna odpowiedź! Zawsze przeoczyłem długie nawrócenia, teraz mogę je zrozumieć i jak pasuje do filozofii rubinu. –

13

Pasuje filozofię Ruby permisywizmu (w przeciwieństwie do, na przykład, surowość Pythonie):

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

Szczerze mówiąc, myślę, że to jest zbyt liberalne. Jak zauważył Zabba, możesz użyć wartości Kernel#Integer(string) dla ścisłej konwersji.

+3

Nie trzeba używać wyrażeń regularnych. Jeśli chcesz błędów, gdy ciąg nie jest całkowicie liczbą (np. "123hello"), możesz zrobić to tak: 'Integer (" 123hello ")' (wyrzuca 'ArgumentError'). – Zabba

+0

+1 tak, wydaje się nadmiernie permisywny. dobrze powiedziane. – Peter

6

to_i oznacza "przekonwertuj mnie na liczbę całkowitą, jeśli możesz".

Jeśli chcesz "jeśli jesteś bardzo podobny do liczb całkowitych, podaj mi wartość całkowitą, inaczej podaj NoMethodError", a następnie użyj .to_int.

Jest jeszcze jedna kwestia, która pyta o różnicę między to_i i to_int, to_s kontra to_str itp Daj mi znać, jeśli chcesz mi znaleźć go dla Ciebie.

6

Protokół to_i mówi, że musi zwrócić Integer i nie musi podnieść wyjątek. Obie sugestie naruszają co najmniej jedną z tych zasad. Więc nie, te nie tylko nie byłyby bardziej logiczne, byłyby po prostu nieważne.

Należy jednak zauważyć, że nil nie odpowiada na to_int. Gdyby zareagował na , to byłby on rzeczywiście "nielogiczny".

+1

Fakt, że protokół mówi, że 'to_i' musi zwracać liczbę całkowitą, nie czyni tego zachowania logicznym, po prostu czyni go zgodnym (biorąc pod uwagę, lepiej jest być zgodnym nawet, jeśli nielogicznym). –

1

Jeśli zdarzy ci się być w Rails można użyć try:

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