2013-02-08 37 views
10

Tôi đang tìm cách 'bản đồ' một mục duy nhất trong Ruby.Bản đồ Ruby() cho một đối tượng duy nhất

Tôi muốn gọi hàm này và chuyển cho nó một khối, đối tượng sẽ được mang đến khối, và sau đó kết quả của khối sẽ được trả lại cho người gọi. Chính xác những gì bản đồ nào, nhưng đối với một phần tử duy nhất.

Động cơ là đôi khi bạn tạo ra các đối tượng chỉ được sử dụng để xây dựng một thứ khác. Đối tượng ban đầu sau đó không còn cần thiết nữa. Nó sẽ là tốt đẹp để chỉ cần đặt chuyển đổi thành một khối và loại bỏ tạm thời.

Ví dụ: giả sử rằng tôi muốn tạo số nguyên đại diện cho kết hợp tháng/năm. Cho ngày hôm nay, mã sẽ giống như thế:

day = Date.today 
month_number = day.year * 100 + day.month 

tôi thực sự thích nó nếu tôi có thể làm điều gì đó như:

month_number = Date.today.some_function { |d| d.year * 100 + d.month } 

Nhưng tôi không biết những gì 'some_function' là (hoặc nếu nó còn tồn tại).

Nếu có cách nào Ruby xử lý một cái gì đó như thế này, tôi là tất cả tai. Tôi nhận thức được các lớp vá khỉ, nhưng tôi đang tìm cách xử lý những trường hợp đó một chút thoáng qua.

+0

[ 'Object # tap'] (http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap) là rất gần nhưng nó doesn' t trả về giá trị của khối ... – maerics

+1

Một cái gì đó như thế nào? m = lambda {| d | d.year * 100 + d.month} .call (Date.today) – Kaeros

+0

Xem câu trả lời của @jondavidjohn. Được xây dựng trong và không có chi phí ràng buộc proc. –

Trả lời

13

instance_eval là những gì bạn đang tìm kiếm.

month_number = Date.today.instance_eval { |d| d.year * 100 + d.month } 

|d| cũng là tùy chọn và self mặc định theo ngữ cảnh đối tượng.

Điều này có thể đáp ứng nhu cầu của bạn một cách gọn nhẹ hơn.

month_number = Date.today.instance_eval { year * 100 + month } 
+1

Cảm ơn! Đó chính xác là những gì tôi cần. –

+0

Dường như | d | cũng là tùy chọn (tự nó sẽ là cá thể trong khi thực thi khối). Vì vậy, những điều sau đây cũng sẽ hoạt động: Date.today.instance_eval {year * 100 + month} –

+0

Cảm ơn, Nó đã làm việc cho tôi. –

3

Mã dựng sẵn của Ruby Object#tap đóng nhưng không trả lại giá trị của khối.

Dưới đây là một ý tưởng:

class Object 
    def sap 
    yield self 
    end 
end 

eleven = 10.sap { |x| x + 1 } # => 11 
month_number = Date.today.sap { |d| d.year * 100 + d.month } # => 201202 
+0

Tại sao bạn khỉ vá nếu bạn không phân nửa? xem câu trả lời của tôi dưới đây. – jondavidjohn

+1

+1 cho một cú pháp ngắn, đẹp, nhưng tôi nghĩ rằng việc sử dụng instance @evondavidjohn của instance_eval là chính xác hơn nhờ vào được xây dựng. –

+2

Trong khi 'instance_eval' làm việc tương tự, nó cũng cho thấy các biến thành viên của đối tượng đích, phá vỡ rào cản giao diện/triển khai. Đây không phải là một mối quan tâm an ninh như một cơ hội để vô tình thổi tắt chân của bạn. IMHO khỉ vá là hợp lý trong trường hợp này. – maerics

15

Sử dụng instance_eval như trong câu trả lời jondavidjohn 's là một trong những con đường để đi, nhưng nó có chi phí cho reassigning self. Tính năng này đã từng là proposed in Ruby core, nhưng đã bị từ chối và bị rút lại. Sử dụng các giải pháp được trình bày ở đó bởi một trong những nhà phát triển KNU Ruby (Akinori musha), bạn có thể viết như thế này:

month_number = Date.today.tap{|d| break d.year * 100 + d.month} 

sử dụng tap, điều thêm duy nhất bạn cần làm là đặt break vào đầu của khối .


require 'benchmark' 

n = 500000 
Benchmark.bm do |x| 
    x.report{n.times{Date.today.instance_eval{year * 100 + month}}} 
    x.report{n.times{Date.today.instance_eval{|d| d.year * 100 + d.month}}} 
    x.report{n.times{Date.today.tap{|d| break d.year * 100 + d.month}}} 
end 

     user  system  total  real 
    2.130000 0.400000 2.530000 ( 2.524296) 
    2.120000 0.400000 2.520000 ( 2.527134) 
    1.410000 0.390000 1.800000 ( 1.799213) 
+1

+1 cho câu trả lời có nhiều khả năng được nhóm lõi ưa chuộng nhất. Tôi vẫn đang học một số từ trong và ngoài của Ruby và hành vi phá vỡ các khối là mới đối với tôi. Trong trường hợp này, tôi thành thực tìm thấy hành vi của ngôn ngữ discomfiting. –

+1

+1 cho điểm chuẩn. Cảm ơn bạn! –

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