2013-07-28 31 views
10

Tôi đang làm việc trên một giải pháp cho bản vẽ kỹ thuật (svg/ruby). Tôi muốn thao tác hình chữ nhật, và có một phương pháp add! trong lớp này:Tại sao không có phương pháp sao chép sâu trong Ruby?

class Rect 
    def add!(delta) 
    @x1+=delta 
    ... # and so on 
    self 
    end 
end 

Tôi cũng cần một phương pháp add trả lại một Rect, nhưng không phải thao tác self:

def add(delta) 
    r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here 
    r.add! delta 
end 

dupclone không làm việc của tôi nhưng:

def copy; Marshal.load(Marshal.dump(self)); end 

.

Tại sao một chức năng cơ bản như vậy không tồn tại trong Ruby thuần túy? Vui lòng không cho tôi biết rằng tôi có thể đảo ngược addadd!, cho phép add thực hiện công việc và add! gọi điện.

+7

Tại sao nó không tồn tại? Nó có: 'Marshal.dump' +' Marshal.load'. Bạn có thể đặt tên một số ngôn ngữ lập trình có bản sao sâu về mức độ ngôn ngữ không? –

+0

điểm của bạn, tôi nghĩ, rằng tôi giống như một đứa trẻ hư hỏng với Ruby, tìm kiếm tất cả ở đây, mà tôi bị mất ở những nơi khác: -D – halfbit

+0

"Tại sao" làm cho câu hỏi này khó/không thể cho bất cứ ai khác hơn Matz, et al., để trả lời. –

Trả lời

5

Tôi không chắc tại sao không có phương pháp sao chép sâu trong Ruby, nhưng tôi sẽ cố gắng thực hiện phỏng đoán dựa trên thông tin tôi có thể tìm thấy (xem liên kết và trích dẫn bên dưới dòng). Đánh giá từ thông tin này, tôi chỉ có thể suy luận rằng lý do Ruby không có phương pháp sao chép sâu là vì nó rất hiếm khi cần thiết và trong một vài trường hợp cần thiết, có những cách tương đối đơn giản khác hoàn thành nhiệm vụ tương tự:

Như bạn đã biết, sử dụng Marshal.dumpMarshal.load hiện là cách được khuyến nghị để thực hiện việc này. Đây cũng là cách tiếp cận được đề xuất bởi Lập trình Ruby (xem phần trích dẫn bên dưới).

Ngoài ra, có ít nhất 3 triển khai có sẵn được tìm thấy trong các đá quý sau: deep_cloneable, deep_cloneruby_deep_clone; đầu tiên là phổ biến nhất.


Thông tin liên quan

Dưới đây là a discussion over at comp.lang.ruby mà có thể làm sáng tỏ về vấn đề này. Có another answer here với một số cuộc thảo luận liên quan, nhưng tất cả đều trở lại sử dụng Marshal.

Không có bất kỳ đề cập nào về sao chép sâu trong Programming Ruby, nhưng có một vài đề cập trong số The Ruby Programming Language. Dưới đây là một vài trích đoạn liên quan:

[...]

Một sử dụng cho Marshal.dumpMarshal.load là tạo ra các bản sao sâu của các đối tượng:

def deepcopy(o) 
    Marshal.load(Marshal.dump(o)) 
end 

[...]

... định dạng nhị phân được sử dụng bởi Marshal.dumpMarshal.load là phụ thuộc phiên bản và các phiên bản mới hơn o f Ruby không được bảo đảm là có thể đọc các đối tượng được khắc phục bằng các phiên bản cũ của Ruby.

[...]

Lưu ý rằng tập tin và I/O suối, cũng như phương pháp và Binding đối tượng, quá năng động để được marshalled; sẽ không có cách nào đáng tin cậy để khôi phục trạng thái của họ.

[...]

Thay vì thực hiện một bản sao sâu phòng thủ của mảng, chỉ cần gọi to_enum vào nó, và vượt qua các điều tra viên kết quả thay vì các mảng riêng của mình. Thực tế, bạn đang tạo một đối tượng proxy có thể đếm được nhưng không thay đổi được cho mảng của bạn.

+2

đây không chỉ là câu trả lời; kết luận của tôi - lấy liên kết của bạn trong mối quan tâm - là, (sâu) sao chép một đối tượng là (nhiều hơn hoặc ít thường xuyên hơn) một con trỏ cho một thiết kế xấu. – halfbit

+0

Về điểm cuối cùng liên quan đến việc sử dụng to_enum. Tôi đã thử điều này nhưng nó không hoạt động như mong đợi. Tôi đang sử dụng Ruby 2.2.0 a = [1,2,3,4] => [1, 2, 3, 4] b = a.to_enum => # <ĐTV: [1, 2, 3, 4]: mỗi> một << 5 => [1, 2, 3, 4, 5] b => # <ĐTV: [1, 2, 3, 4, 5]: mỗi> Cách tạo enumerable tạo ra một đối tượng poxy bất biến cho mảng? – RubyMiner

0

Tại sao bạn không thể sử dụng một cái gì đó như thế này:

new_item = Item.new(old_item.attributes) 
new_item.save! 

này sẽ sao chép tất cả các thuộc tính từ mặt hàng hiện có để một hình mới, không có vấn đề. Nếu bạn có các đối tượng khác, bạn chỉ có thể sao chép chúng riêng lẻ.

Tôi nghĩ rằng đó là cách nhanh nhất để sao chép một đối tượng

+0

Nếu bạn đang đối phó với các đối tượng kiểu ActiveRecord, điều đó có thể làm việc, có lẽ. Nhưng điều đó rõ ràng sẽ không hoạt động đối với bất kỳ đối tượng Ruby nào. – flajann

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