2012-06-24 25 views
59

Tôi đang học Ruby và tôi đã thấy một vài phương pháp khiến tôi khó hiểu một chút, đặc biệt là to_s vs to_str (và tương tự, to_i/to_int, to_a/to_ary, & to_h/to_hash). Những gì tôi đã đọc giải thích rằng biểu mẫu ngắn hơn (ví dụ: to_s) dành cho chuyển đổi rõ ràng trong khi biểu mẫu dài hơn dành cho chuyển đổi tiềm ẩn.to_s so với to_str (và to_i/to_a/to_h so với to_int/to_ary/to_hash) trong Ruby

Tôi thực sự không hiểu làm thế nào to_str thực sự sẽ được sử dụng. Có gì khác hơn là một chuỗi bao giờ xác định to_str? Bạn có thể đưa ra một ứng dụng thực tế cho phương pháp này không?

Trả lời

71

Lưu ý đầu tiên mà tất cả điều này áp dụng cho mỗi cặp “ngắn” (ví dụ to_s/to_i/to_a/to_h) và “dài” (ví dụ to_str/to_int/to_ary/to_hash) phương pháp ép buộc trong Ruby (đối với họ các loại tương ứng) vì tất cả chúng đều có cùng ngữ nghĩa.


Chúng có ý nghĩa khác. Bạn không nên triển khai to_str trừ khi đối tượng hoạt động giống như một chuỗi, thay vì chỉ là thể hiện được bằng một chuỗi. Lớp lõi duy nhất triển khai to_str là chính chuỗi.

Từ lập trình Ruby (trích dẫn từ this blog post, đó là giá trị đọc tất cả):

[to_ito_s] không phải là đặc biệt nghiêm ngặt: nếu một đối tượng có một số loại đại diện đàng hoàng như là một chuỗi , ví dụ, nó có thể có một phương pháp to_s… [to_intto_str] là các hàm chuyển đổi nghiêm ngặt: bạn chỉ thực thi chúng nếu đối tượng [của bạn] có thể được sử dụng một cách tự nhiên ở mọi nơi một chuỗi hoặc một số nguyên.

Older Ruby documentation from the Pickaxe có này để nói:

Không giống như to_s, được hỗ trợ bởi hầu hết các lớp học, to_str thường được thực hiện chỉ bởi những lớp học mà hành động như chuỗi.

Ví dụ, ngoài Integer, cả Float & Numeric thực hiện to_int (to_i 's tương đương với to_str) vì cả hai trong số họ có thể dễ dàng thay thế cho một Integer (họ là tất cả thực sự con số). Trừ khi lớp học của bạn có mối quan hệ chặt chẽ tương tự với Chuỗi, bạn không nên triển khai to_str.

+7

Andrew, cảm ơn. Nhưng theo nghĩa thực tế, điều đó có nghĩa là "những lớp học đó hoạt động như dây?" Điều đó có nghĩa là chúng thực hiện các phương thức giống như Strings? Và những gì khác sẽ to_str trở lại khác hơn là tự nếu đối tượng đã hoạt động như một chuỗi? –

+1

@JeffStorey Có. Trừ khi lớp của bạn có thể được thay thế cho/bởi một String, bạn không nên thực hiện 'to_str'. Việc thực thi chuỗi 'to_s' và' to_str' của chuỗi làm điều đó: tự trả về. Việc thực hiện 'to_str' là một cách để xác nhận rằng bạn hành động giống như một String. Nhiều phương thức cốt lõi sử dụng 'to_str' theo cách này. Bài đăng trên blog mà tôi trích dẫn là đáng đọc ':)'. –

+0

Andrew, cảm ơn. Tôi đã đọc bài đó và tôi vẫn chưa rõ lắm. Có bao giờ một thời gian mà bạn có thể thực hiện to_str? Đó là phần tôi thực sự bối rối về ... Tôi không thể nghĩ ra một ví dụ thực tế một cách dễ dàng. –

16

Để hiểu xem bạn có nên sử dụng/triển khai to_s/to_str, hãy xem một số ví dụ. Nó được tiết lộ để xem xét khi phương pháp này thất bại.

1.to_s    # returns "1" 
Object.new.to_s  # returns "#<Object:0x4932990>" 
1.to_str   # raises NoMethodError 
Object.new.to_str # raises NoMethodError 

Như chúng ta có thể thấy, to_s là hạnh phúc để biến bất kỳ đối tượng thành một chuỗi. Mặt khác, to_strđặt ra lỗi khi tham số của nó không giống như một chuỗi.


Bây giờ, hãy xem Array#join.

[1,2].join(',')  # returns "1,2" 
[1,2].join(3)  # fails, the argument does not look like a valid separator. 

Nó rất hữu ích mà Array#join chuyển thành chuỗi các mục trong mảng (bất cứ điều gì họ thực sự đang có) trước khi gia nhập chúng, vì vậy Array#join cuộc gọi to_s trên chúng.

Tuy nhiên, dấu phân tách được cho là chuỗi - ai đó đang gọi [1,2].join(3) có thể đang phạm sai lầm. Đây là lý do tại sao Array#join gọi to_str trên dấu phân cách.


Nguyên tắc tương tự dường như giữ cho các phương pháp khác. Cân nhắc to_a/to_ary trên băm:

{1,2}.to_a  # returns [[1, 2]], an array that describes the hash 
{1,2}.to_ary # fails, because a hash is not really an array. 

Nói tóm lại, đây là cách tôi nhìn thấy nó:

  • gọi to_s để có được một chuỗi mô tả các đối tượng.
  • gọi to_str để xác minh rằng một đối tượng thực sự hoạt động như một chuỗi.
  • triển khai to_s khi bạn có thể tạo chuỗi mô tả đối tượng của mình.
  • triển khai to_str khi đối tượng của bạn hoàn toàn có thể hoạt động giống như một chuỗi.

Tôi nghĩ trường hợp khi bạn có thể tự mình thực hiện to_str thì có thể là lớp ColoredString - một chuỗi có màu gắn liền với nó. Nếu có vẻ rõ ràng đối với bạn, việc chuyển dấu phẩy màu đến join không phải là lỗi và phải dẫn đến "1,2" (mặc dù chuỗi đó không được tô màu), sau đó làm triển khai to_str trên ColoredString.

Các vấn đề liên quan