2013-05-09 49 views
8

Tôi đang tìm cách làm sâu (tại thời điểm này, cạn có thể đủ) bản sao của một đối tượng may mắn.Perl: Làm thế nào để sao chép sâu một đối tượng may mắn?

Foo Lớp

package Foo; 
our $FOO = new Foo;  # initial run 

sub new { 
    my $class = shift; 
    my $self = {}; 
    bless $self, $class; 
    return $self; 
} 

Chương trình chính

use Foo; 
my $copy = $Foo::FOO;  # instead of creating a ref, want to deep copy here 
$copy->{bar} = 'bar'; 

bar xuất hiện trong cả hai $Foo::FOO$copy. Tôi nhận ra rằng tôi có thể tạo một bản sao của đối tượng bằng cách thiết lập nó như là , nhưng sau đó nó sẽ không còn được ban phước; ngoài ra, điều này sẽ chỉ làm việc cho các cấu trúc dữ liệu đơn giản (ngay bây giờ không phải là một vấn đề). Cách duy nhất để sao chép theo cách này và sau đó chúc lành cho sau (ví dụ: $copy = bless { %{$Foo::FOO} }, q{Foo};)?

Tôi đang cố gắng tránh sử dụng Moose, Clone hoặc các mô-đun/gói không phải cốt lõi khác, vì vậy, hãy nhớ điều đó khi trả lời. Được in đậm để nổi bật hơn :)

+0

Giải pháp được chấp nhận có thể thay đổi: lưu ý rằng việc sao chép cấu trúc dữ liệu đơn giản hơn, nhưng không giải quyết được việc sao chép sâu hoặc thậm chí nhiều cấu trúc lớp nâng cao hơn; đó là câu hỏi ban đầu của tôi. Lưu ý rằng câu trả lời đã chọn có thể thay đổi trong tương lai. – vol7ron

Trả lời

10

Sao chép phải là một phần của API. Người dùng mô-đun của bạn sẽ không bao giờ biết những hành động đặc biệt nào được yêu cầu khi tạo một đối tượng mới (xem xét đăng ký từng đối tượng trong một băm my trong gói của bạn).

Vì vậy, hãy cung cấp phương thức clone cho các đối tượng của bạn. Bên trong nó, bạn có thể sử dụng bất kỳ thủ đoạn bẩn nào bạn thích:

sub clone { 
    my $self = shift; 
    my $copy = bless { %$self }, ref $self; 
    $register{$copy} = localtime; # Or whatever else you need to do with a new object. 
    # ... 
    return $copy; 
} 
+0

Tôi nghĩ rằng đây có thể là cách để đi. Đây sẽ là bước tiếp theo của tôi, tôi đã hy vọng Perl có cái gì đó được xây dựng trong đó đã làm điều tương tự, vì vậy mà tôi sẽ không phải sưng lên đối tượng của tôi, nhưng cảm ơn! – vol7ron

+0

Additionaly 'my $ dictionary = sao chép $ book;' đọc tốt hơn rất nhiều. Mặc dù đây là câu trả lời được chấp nhận, người dùng nên lưu ý rằng điều này là nhiều hơn cho bản sao nông của cấu trúc dữ liệu đơn giản, và sẽ không giải quyết sao chép sâu, hoặc thậm chí nhiều cấu trúc lớp học tiên tiến hơn. – vol7ron

+2

'bless {% $ self}, kỹ thuật ref $ self' sẽ chỉ làm một bản sao nông. Các thuộc tính của '$ self' là các tham chiếu sẽ không được nhân bản. Ví dụ: '$ obj -> {ponies} = [qw (Dash Sparkle Jack)]; $ clone = $ obj-> sao chép; đẩy @ {$ clone -> {ponies}}, "Pinkie" 'sẽ sửa đổi cả hai đối tượng. – Schwern

9

use Storable 'dclone';?

$ corelist Storable 

Storable was first released with perl v5.7.3 

Thêm vào đó bạn có thể fiddle xung quanh với móc storable để khẳng định kiểm soát tốt hơn sao chép đối tượng của bạn (không phải là tôi đã làm được điều đó, nhưng đó là những gì những tuyên bố tài liệu).

3

Không có cách nào tốt cho chương trình gọi điện thoại để biết những gì "sao chép một đối tượng" đòi hỏi, do đó, một đối tượng nên biết làm thế nào để sao chép chính nó. OO Perl không cung cấp cho bạn bất kỳ sự giúp đỡ ở đây, nhưng điều thường làm là một cái gì đó như thế này:

package Car; 

sub clone { 
    my ($self) = @_; 

    return $self->new(
     (map { $_ => $self->$_() } qw/make model/), # built-in types 
     engine => $self->engine->clone(), # copying an object 
    ); 
} 
4

my $copy = bless { %$self }, ref $self; trong câu trả lời @ Chorba là không đủ. Nó sẽ chỉ sao chép lớp đầu tiên. Mọi tham chiếu được lưu trữ trong $self sẽ không được sao chép. Hậu quả của việc này là ...

$obj->{ponies} = [qw(Dash Sparkle Jack)]; 
$clone = $obj->clone; 
push @{$clone->{ponies}}, "Pinkie"; 
print join ", ", @{$obj->{ponies}}; # Dash Sparkle Jack Pinkie 

Bạn có thể không có bất kỳ tham chiếu nào, nhưng có thể bạn sẽ sau này. Hoặc ai đó khác sẽ dính vào một đối tượng của bạn. Hoặc họ sẽ phân lớp và thêm một.

Bạn có thể viết thói quen nhân bản sâu, nhưng nó không đơn giản. Tôi rất muốn giới thiệu sử dụng Clone. Nó không có phụ thuộc và vì vậy bạn có thể chỉ cần sao chép Clone.pm vào dự án của bạn.

Phương án thay thế khác là Storable::dclone, được đề cập bởi @Zaid, đã được sử dụng trong một thời gian dài.

Không có vấn đề gì bạn sử dụng, cung cấp một phương pháp nhân bản trên lớp học của bạn là điều phải làm, ngay cả khi nó chỉ là một wrapper xung quanh Clone hoặc Storable :: dclone. Điều này sẽ bảo vệ người dùng đối tượng của bạn khỏi các chi tiết về cách đối tượng của bạn được nhân bản.

+0

Tôi sẽ nói rằng đôi khi bạn muốn * muốn * hai đối tượng nhân bản vô tính ở lại trỏ đến cùng một tham chiếu. Ví dụ, nếu lớp 'Person' của bạn có thuộc tính' employ' trỏ đến một đối tượng đại diện cho Tổ chức AcmeCorp ', bạn có thể sẽ không muốn nhân bản Bob cũng sao chép AcmeCorp. Những loại quyết định này chỉ có thể được thực hiện trên cơ sở từng lớp học, và cần được ghi chép kỹ lưỡng. – tobyink

+0

@tobyink Có, chính xác tại sao nhân bản được thực hiện thông qua '$ obj-> clone' thay vì' clone ($ obj) '. Các đối tượng tốt nhất có thể quyết định làm thế nào nó nên được nhân bản. Những gì một phương pháp 'clone' nên làm là bị bệnh xác định. Nó là một bản sao nông? Một bản sao sâu? Một bản sao "như tôi thấy phù hợp"? Các hành vi/giao diện của phương pháp nhân bản của bạn nên được suy nghĩ và xác định. Bạn có thể cần một số phương pháp nhân bản. – Schwern

0

Tôi xin lỗi, tôi không thể nhận thấy câu này:

* Tôi đang cố gắng để tránh sử dụng Moose, Clone, hoặc khác không-Core modules/gói, vì vậy hãy giữ cho rằng trong tâm trí khi trả lời . Được in đậm để nó nổi bật hơn :) *

để câu trả lời này không thể được chấp nhận!

#!/usr/bin/env perl -w 
use strict; 
use warnings; 
use Storable; 
use Data::Dumper; 

my $src = { 
    foo => 0, 
    bar => [0,1] 
}; 

$src -> {baz} = $src; 
my $dst = Storable::dclone($src); 
print '$src is : '.Dumper($src)."\n"; 
print '$dst is : '.Dumper($dst)."\n"; 
+0

Giải thích cách giải quyết vấn đề. –

+0

Xin chào, Rahil Wazir, có URL trang web: http: //search.cpan.org/~ams/Storable-2.45/Storable.pm, bạn có thể tìm hiểu: "Storable cung cấp cho bạn giao diện dclone không tạo ra trung gian vô hướng nhưng thay vì đóng băng cấu trúc trong một số không gian bộ nhớ nội bộ và sau đó ngay lập tức làm hỏng nó ra. "," Trái tim của Storable được viết bằng C cho tốc độ phong nha thêm tối ưu hóa cấp thấp đã được thực hiện khi thao tác perl internals, để hy sinh đóng gói vì lợi ích của tốc độ lớn hơn. "; Tôi hy vọng rằng mọi thứ có thể giúp bạn. –

+1

Bạn có thể chỉnh sửa phần này vào câu trả lời của mình thay vì bình luận hay không. –