2010-04-27 46 views
6

Tôi đang cố gắng viết một số mã trừu tượng để tìm kiếm thông qua danh sách các đối tượng tương tự cho đối tượng đầu tiên có thuộc tính khớp với các giá trị cụ thể. Để làm điều này, tôi cần phải gọi một loạt các phương thức accessor và kiểm tra tất cả các giá trị của chúng từng cái một. Tôi muốn sử dụng tính trừu tượng như sau:Trong Perl, làm thế nào tôi có thể gọi một phương thức có tên tôi có trong một chuỗi?

sub verify_attribute { 
    my ($object, $attribute_method, $wanted_value) = @_; 
    if (call_method($object, $attribute_method) ~~ $wanted_value) { 
     return 1; 
    } 
    else { 
     return; 
    } 
} 

Sau đó, tôi có thể lặp qua băm có khóa là tên phương thức truy cập và giá trị của nó là giá trị tôi đang tìm kiếm cho các thuộc tính đó. Ví dụ, nếu băm đó được gọi là %wanted, tôi có thể sử dụng mã như thế này để tìm đối tượng tôi muốn:

my $found_object; 
FINDOBJ: foreach my $obj (@list_of_objects) { 
    foreach my $accessor (keys %wanted) { 
     next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor}); 
    } 
    # All attrs verified 
    $found_object = $obj; 
    last FINDOBJ; 
} 

Tất nhiên, vấn đề duy nhất là call_method không exsit. Hay không? Làm thế nào tôi có thể gọi một phương thức nếu tôi có một chuỗi có chứa tên của nó? Hoặc là có một giải pháp tốt hơn cho toàn bộ vấn đề này?

Trả lời

5
my $found_object; 
FINDOBJ: foreach my $obj (@list_of_objects) { 
    foreach my $accessor (keys %wanted) { 
    next FINDOBJ unless $obj->$accessor() == $wanted{$accessor}; 
    } 
    # All attrs verified 
    $found_object = $obj; 
    last; 
} 

Có, bạn có thể gọi các phương pháp theo cách này. Không có chuỗi (hoặc bất kỳ khác) eval tham gia. Ngoài ra, thay == với eq hoặc =~ tùy thuộc vào loại dữ liệu ...

Hoặc, đối với một số khoản tín dụng bổ sung, làm nó theo cách chức năng: (tất cả() nên thực sự là một phần của Danh sách :: util!)

use List::Util 'first'; 

sub all (&@) { 
    my $code = shift; 
    $code->($_) || return 0 for @_; 
    return 1; 
} 

my $match = first { 
        my $obj = $_; 
        all { $obj->$_ == $attrs{$_} } 
         keys %wanted 
        } @list_of_objects; 

Cập nhật: Phải thừa nhận rằng, giải pháp đầu tiên là ít bị làm xáo trộn, do đó, nó phù hợp hơn. Nhưng khi ai đó trả lời câu hỏi, bạn có thêm một chút đường để làm cho nó thú vị cho chính mình, quá! ;-)

+0

Ye ah, tôi đã chỉ ra điều này trong một vài seoncds trước đây bằng thử và sai. Mát mẻ. –

+1

Tôi chỉ sử dụng 'Danh sách :: AllUtils'. Hoặc 'Util :: Any qw (: all)'. Nhưng trong mã ví dụ của tôi, tôi cố gắng gắn bó với cốt lõi. –

+0

Tôi tin rằng để làm việc này bạn phải vô hiệu hóa các kiểm tra nghiêm ngặt với 'không nghiêm ngặt;' (không nhất thiết trên toàn cầu) - đúng không? –

0

cách chức năng là mát mẻ, nhưng đối với núm vú cao su như tôi quy tắc eval:

test.pl

#!/usr/bin/perl -l 
use F; 
my $f = F->new(); 

my $fun = 'lol'; # method of F 

eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var 

F.pm

package F; 

sub new 
{ 
    bless {}; 
} 


sub lol 
{ 
    print "LoL"; 
} 
1; 

[root @ ALT-24 root] # perl test.pl

LoL

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