Tôi có một số hàm tiện ích bậc cao hơn tham chiếu mã và áp dụng mã đó cho một số dữ liệu. Một số hàm này yêu cầu bản địa hóa các biến trong khi thực hiện các chương trình con. Lúc đầu, tôi đã sử dụng caller
để xác định gói để bản địa hoá vào, một cách tương tự như trong ví dụ này reduce
chức năng:Trong Perl, cách đáng tin cậy nhất để xác định gói của coderef là gì?
sub reduce (&@) {
my $code = shift;
my $caller = caller;
my ($ca, $cb) = do {
no strict 'refs';
map \*{$caller.'::'.$_} => qw(a b)
};
local (*a, *b) = local (*$ca, *$cb);
$a = shift;
while (@_) {
$b = shift;
$a = $code->()
}
$a
}
Ban đầu kỹ thuật này làm việc tốt, tuy nhiên ngay sau khi tôi cố gắng viết một wrapper chức năng xung quanh chức năng thứ tự cao hơn, tìm ra người gọi chính xác trở nên phức tạp.
sub reduce_ref (&$) {&reduce($_[0], @{$_[1]})}
Bây giờ để cho reduce
để làm việc, tôi sẽ cần một cái gì đó như:
my ($ca, $cb) = do {
my $caller = 0;
$caller++ while caller($caller) =~ /^This::Package/;
no strict 'refs';
map \*{caller($caller).'::'.$_} => qw(a b)
};
Tại thời điểm này nó đã trở thành một vấn đề mà gói để bỏ qua, kết hợp với kỷ luật không bao giờ sử dụng chức năng từ bên trong những gói đó. Phải có một cách tốt hơn.
Nó chỉ ra rằng chương trình con các hàm bậc cao hơn lấy làm đối số chứa đủ siêu dữ liệu để giải quyết vấn đề. Giải pháp hiện tại của tôi là sử dụng mô-đun intropection B
để xác định việc biên dịch stash của chương trình con được truyền vào trong chương trình con. Bằng cách đó, không có vấn đề gì xảy ra giữa việc biên dịch mã và thực thi của nó, hàm bậc cao hơn luôn biết gói chính xác để bản địa hóa thành.
my ($ca, $cb) = do {
require B;
my $caller = B::svref_2object($code)->STASH->NAME;
no strict 'refs';
map \*{$caller.'::'.$_} => qw(a b)
};
Vì vậy, câu hỏi cuối cùng của tôi là nếu đây là cách tốt nhất để xác định gói của người gọi trong tình huống này? Có cách nào khác mà tôi không nghĩ đến? Có một số lỗi đang chờ xảy ra với giải pháp hiện tại của tôi không?
Điều này có vẻ phụ thuộc rất nhiều vào việc triển khai ... Bạn tự tin rằng không có điều nào trong số này sẽ thay đổi trong các phiên bản tương lai của Perl?Nó sẽ không được đơn giản và mạnh mẽ hơn để sử dụng các đối tượng thay vì các chức năng thô, có mỗi đối tượng lưu trữ một chức năng và cũng nhớ các gói thích hợp? – Nemo