2015-01-21 19 views
5

Tôi đang cố gắng tạo một chức năng sắp xếp có sẵn trong một trong các gói (hướng đối tượng) chấp nhận một khối và tạo sẵn $ a và $ b như tiêu chuẩn Perl sort.Chức năng sắp xếp của perl trong một đối tượng

Thứ nhất, một phiên bản đơn giản của những gì tôi đang cố gắng để làm trong gói có chứa các chức năng bọc loại:

# In package My::Object 
sub sort { 
    my $self = shift; 
    my $block = \&{shift @_}; 

    return sort $block @{$self->{arrayRef}}; # I want to use the passed in block with array data contained in this object 
} 

Và sau đó là một ví dụ về một khách hàng đi qua một khối trong đó xác định comparitor để chạy cho loại:

my $obj = My::Object->new([3, 1, 5, 6, 2, 4]); # As an example, these values will be come arrayRef from above 
my @sortedVals = $obj->sort({ $a < $b }); 

Có cách nào để làm những gì tôi đang cố gắng làm trong khi vẫn có thể sử dụng số sort của Perl không?

Trả lời

8

Chủ yếu là.

Để sử dụng cú pháp trần-như-chương trình con, bạn cần sử dụng &prototype. Nói chung bạn nên tránh nguyên mẫu, nhưng việc chuyển một chương trình con như là một khối trống là một trong số ít lần điều này được chấp nhận. Thật không may, bởi vì chúng phải được xác định và áp dụng vào thời gian biên dịch, các nguyên mẫu không hoạt động trên các phương thức. Vì vậy, bạn phải sử dụng cú pháp chương trình con ẩn danh đầy đủ, sub { ... }.

my @sortedVals = $obj->sort(sub { $a <=> $b }); 

$a$b là globals của gói các chương trình con loại được khai báo trong (giả sử đây là Some::Caller). Khi chạy bên trong lớp học của bạn, sắp xếp sẽ đặt $My::Object::a$My::Object::b nhưng chương trình con sẽ tìm kiếm $Some::Caller::a$Some::Caller::b. Bạn có thể giải quyết vấn đề này bằng cách đánh dấu các số $a$b của mình vào số $a$b.

sub sort { 
    my $self = shift; 
    my $block = shift; 

    no strict 'refs'; 
    local *{caller.'::a'} = *a; 
    local *{caller.'::b'} = *b; 

    return sort $block @{$self->{arrayRef}}; 
} 

local tạo một bản sao tạm thời của một toàn cầu trong suốt thời gian của khối và điều này bao gồm các chương trình con khác gọi, vì vậy đây sẽ thực hiện việc phân loại. Sau đó, khi phương thức được thực hiện, giá trị sẽ hoàn nguyên về giá trị của nó.

Hình cầu perl được lưu trữ trong typeglobs chứa tất cả các biến toàn cầu có cùng tên. *a chứa $a@a%a. Bằng cách sao chép typeglob của người gọi, khi $My::Object::a thay đổi, số $a của người gọi cũng sẽ thay đổi. Họ là bí danh.

Cú pháp *{...} cho phép bạn nhận được biến toàn cục theo tên sử dụng biến hoặc biểu thức khác. Đây được gọi là symbolic reference. Bây giờ chúng ta có thể lấy số *a của người gọi. Sử dụng cú pháp này thường là một sai lầm, vì vậy bạn phải tắt strict khác Perl sẽ không cho phép bạn làm điều đó.

+2

Đánh giá cao bài đăng của bạn trên SO. –

+0

'The * {...} cú pháp tham chiếu biến toàn cầu theo tên của nó.' Điều đó có vẻ giống như một cách hài hước để mô tả cú pháp đó - đặc biệt là sau khi giải thích cái * typeglob * là gì. Cú pháp đó là một cách khác để viết một * typeglob *, trong đó một * typeglob * đại diện cho tất cả các biến toàn cục với tên được chỉ định ..... – 7stud

+0

Gán tất cả các biến 'a' toàn cầu của gói hiện tại, * typeglob * '* a', cho tất cả các biến 'a' toàn cầu của người gọi, * typeglob * '* {caller. ':: a'}' làm cho các biến 'a' toàn cục của gói hiện hành trở thành bí danh cho các biến 'a' toàn cầu của gói gọi .Điều đó có nghĩa là khi bạn thay đổi biến 'a' toàn cầu trong gói hiện tại, nó sẽ thay đổi biến 'a' toàn cầu trong gói của người gọi. * – 7stud

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