Các vô hướng được trả về bởi :lvalue
không được sao chép.
Các vô hướng được trả về bởi người đăng ký XS không được sao chép.
Các vô hướng được trả về bởi hàm (toán tử có tên) không được sao chép.
Các vô hướng được trả về bởi các người đăng ký khác được sao chép.
Nhưng đó là trước khi bất kỳ bài tập nào được đưa vào chơi. Nếu bạn gán các giá trị trả về cho một biến, bạn sẽ sao chép chúng (một lần nữa, trong trường hợp của một Perl bình thường).
Điều này có nghĩa là my $y = sub { $x }->();
bản sao $x
hai lần!
Nhưng điều đó không thực sự quan trọng vì tối ưu hóa.
Hãy bắt đầu với ví dụ về thời điểm chúng không được sao chép.
$ perl -le'
sub f :lvalue { my $x = 123; print \$x; $x }
my $r = \f();
print $r;
'
SCALAR(0x465eb48) # $x
SCALAR(0x465eb48) # The scalar on the stack
Nhưng nếu bạn loại bỏ :lvalue
...
$ perl -le'
sub f { my $x = 123; print \$x; $x }
my $r = \f();
print $r;
'
SCALAR(0x17d0918) # $x
SCALAR(0x17b1ec0) # The scalar on the stack
Tệ hơn nữa, người ta thường sau lên bằng cách gán vô hướng đến một biến, do đó, một bản sao thứ hai xảy ra.
$ perl -le'
sub f { my $x = 123; print \$x; $x }
my $r = \f(); # \
print $r; # > my $y = f();
my $y = $$r; #/
print \$y;
'
SCALAR(0x1802958) # $x
SCALAR(0x17e3eb0) # The scalar on the stack
SCALAR(0x18028f8) # $y
Về mặt cộng, hãy gán tối ưu hóa để giảm thiểu chi phí sao chép chuỗi.
XS subs và chức năng (nhà khai thác được đặt tên) thường trả về con số tử vong ("TEMP"). Đây là những vô hướng "trên hàng chết". Chúng sẽ tự động bị hủy nếu không có gì bước vào để yêu cầu một tham chiếu đến chúng.
Trong phiên bản cũ hơn của Perl (< 5.20), gán một chuỗi chết cho vô hướng khác sẽ gây ra quyền sở hữu bộ đệm chuỗi được chuyển để tránh phải sao chép bộ đệm chuỗi. Ví dụ: my $y = lc($x);
không sao chép chuỗi được tạo bởi lc
; chỉ cần con trỏ chuỗi được sao chép.
$ perl -MDevel::Peek -e'my $s = "abc"; Dump($s); $s = lc($s); Dump($s);'
SV = PV(0x1705840) at 0x1723768
REFCNT = 1
FLAGS = (PADMY,POK,IsCOW,pPOK)
PV = 0x172d4c0 "abc"\0
CUR = 3
LEN = 10
COW_REFCNT = 1
SV = PV(0x1705840) at 0x1723768
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0x1730070 "abc"\0 <-- Note the change of address from stealing
CUR = 3 the buffer from the scalar returned by lc.
LEN = 10
Trong các phiên bản mới hơn của Perl (≥ 5,20), toán tử gán bao giờ [1] bản chuỗi đệm. Thay vào đó, các phiên bản mới hơn của Perl sử dụng cơ chế copy-on-write ("COW").
$ perl -MDevel::Peek -e'my $x = "abc"; my $y = $x; Dump($x); Dump($y);'
SV = PV(0x26b0530) at 0x26ce230
REFCNT = 1
FLAGS = (POK,IsCOW,pPOK)
PV = 0x26d68a0 "abc"\0 <----+
CUR = 3 |
LEN = 10 |
COW_REFCNT = 2 +-- Same buffer (0x26d68a0)
SV = PV(0x26b05c0) at 0x26ce248 |
REFCNT = 1 |
FLAGS = (POK,IsCOW,pPOK) |
PV = 0x26d68a0 "abc"\0 <----+
CUR = 3
LEN = 10
COW_REFCNT = 2
Ok, cho đến nay, tôi đã chỉ nói về vô hướng. Vâng, đó là vì người đăng ký và chức năng chỉ có thể trả lại số lượng lớn [2].
Trong ví dụ của bạn, vô hướng giao cho @return_value
sẽ được trả lại [3], sao chép, sau đó sao chép một lần thứ hai vào @receiver
bởi sự phân công.
Bạn có thể tránh tất cả điều này bằng cách trả lại tham chiếu đến mảng.
sub f { my @fizbobs = ...; \@fizbobs }
my $fizbobs = f();
Điều duy nhất được sao chép có tham chiếu, vô hướng không xác định đơn giản nhất.
Ok, có lẽ không bao giờ. Tôi nghĩ rằng cần phải có một byte miễn phí trong bộ đệm chuỗi để giữ số COW.
Trong ngữ cảnh danh sách, chúng có thể trả về 0, 1 hoặc nhiều trong số chúng, nhưng chúng chỉ có thể trả về vô hướng.
Toán tử cuối cùng của phụ của bạn là toán tử gán danh sách. Trong ngữ cảnh danh sách, toán tử gán danh sách trả về các vô hướng mà bên trái của nó (LHS) đánh giá. Xem Scalar vs List Assignment Operator để biết thêm thông tin.
* "có lẽ bạn nên bao gồm' return' "*' return' rõ ràng là dành cho ngôn ngữ không phải Perl! Tôi nghĩ rằng nó là rõ ràng hơn (và briefer) chỉ để đánh giá danh sách đó là để được trả lại trong tuyên bố cuối cùng của chương trình con. Trong perls cũ, nó làm chậm mọi thứ xuống để thêm 'return', và chúng tôi rất vui khi chỉ đặt' 1; 'ở cuối mô-đun thay vì' return 1; ' – Borodin
Từ cuốn sách 'Learning perl (6th) p. 74': _Một số lập trình viên muốn sử dụng trả lại mỗi lần có một giá trị trả về, như một phương tiện để ghi lại rằng nó là một giá trị trả về. Bạn không thực sự cần nó, nhưng nó cũng không làm hại gì cả. Tuy nhiên, nhiều lập trình viên của Perl tin rằng đó chỉ là bảy ký tự phụ của việc gõ. _ :) Tôi thích sách perl. :) – jm666