2012-01-22 31 views
11

Tôi đang học lập trình meta trong Ruby và tôi đang thử xác định phương thức còn thiếu thông qua phương thức method_missing và define_method. Tôi nhận được một số hành vi bất ngờ và tự hỏi liệu có ai có thể giải thích điều này không. Đây là lớp học của tôi:Ruby: tại sao lại gọi to_ary?

class X 
    def method_missing(m, *args, &block) 
    puts "method #{m} not found. Defining it." 
    self.class.send :define_method, m do 
     puts "hi from method #{m}" 
    end 
    puts "defined method #{m}" 
    end 
end 

Bây giờ, mã này:

x = X.new 

x.some_method 
puts 
x.some_method 
puts 
puts x 

Tạo đầu ra:

method some_method not found. Defining it. 
defined method some_method 

hi from method some_method 

method to_ary not found. Defining it. 
defined method to_ary 
#<X:0x007fcbc38e5030> 

Những gì tôi không nhận được là phần cuối cùng: tại sao của Ruby gọi to_ary trong một cuộc gọi để đặt? Tại sao Ruby cố chuyển đổi đối tượng của tôi thành một mảng chỉ để in nó?

Tôi đã google xung quanh và tìm thấy những liên kết liên quan:

Đây cũng nói về method_missing và to_ary gotchas, nhưng không cụ thể về lý do tại sao puts sẽ gọi to_ary .

Tôi cũng nên đề cập rằng hành vi không thay đổi khi tôi xác định một to_s, ví dụ:

def to_s 
    "I'm an instance of X" 
end 

Kết quả của "puts x" là sau đó:

method to_ary not found. Defining it. 
defined method to_ary 
I'm an instance of X 

Trả lời

14

puts là một từ đồng nghĩa với $stdout.puts. $ Stdout là một lớp IO, vì vậy nhìn vào tài liệu cho IO.puts:

Viết các đối tượng trao cho ios như với IO # in. Viết một bản ghi phân cách (thường là dòng mới) sau bất kỳ ký tự nào chưa kết thúc bằng một chuỗi mới. Nếu được gọi với đối số mảng, hãy viết mỗi phần tử trên một dòng mới.

Điều này có nghĩa là phương pháp puts nhằm viết nhiều dòng đầu ra. Vì vậy, nó cố gắng gọi phương thức to_ary trên một đối tượng và nếu to_ary được xác định, sau đó in từng phần tử trả về Array trên một dòng mới, khác puts gọi phương thức to_s.

to_ary việc sử dụng nội bộ thực sự không được ghi lại trong tài liệu Ruby (Matz chỉ ra điều này trong Ngôn ngữ lập trình Ruby cuốn sách) của bạn.

Phương pháp printp mặt khác không gọi to_ary, chỉ to_s.

Sidenote: Thú vị, đó to_ary phải trở về thực Array đối tượng, không phải là một đối tượng xác định each phương pháp hay cái gì khác:

class Test 
    def to_ary 
    10.downto(1) 
    end 
end 

puts Test.new 

#TypeError: can't convert Test to Array (Test#to_ary gives Enumerator) 
#  from (irb):28:in `puts' 
#  from (irb):28:in `puts' 
#  from (irb):28 
+0

Cảm ơn. Tôi nghĩ rằng bản chất là "to_ary sử dụng nội bộ thực sự là không tài liệu trong tài liệu Ruby" :) Tôi chỉ cần đọc các tài liệu IO.puts, họ không đề cập đến to_ary rõ ràng, điều này nên được rõ ràng hơn tôi nghĩ. Cảm ơn bạn đã trỏ đến cuốn sách "Ngôn ngữ lập trình Ruby", có thể kiểm tra điều đó. –

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