2009-12-02 31 views
8

Tôi chắc chắn rằng điều này được đề cập trong tài liệu ở đâu đó nhưng tôi không thể tìm thấy nó ... Tôi đang tìm đường cú pháp mà sẽ làm cho nó có thể gọi một phương thức trên một lớp có tên được lưu trữ trong một băm (như trái ngược với một vô hướng đơn giản):Làm cách nào để gọi tên hàm được lưu trữ trong băm trong Perl?

use strict; use warnings; 

package Foo; 
sub foo { print "in foo()\n" } 

package main; 
my %hash = (func => 'foo'); 

Foo->$hash{func}; 

Nếu tôi sao chép $hash{func} vào một biến vô hướng đầu tiên, sau đó tôi có thể gọi Foo->$func tốt ... nhưng những gì là mất tích để cho phép Foo->$hash{func} để làm việc?

(EDIT: Tôi không có ý định làm bất cứ điều gì đặc biệt bằng cách gọi một phương thức trên lớp Foo - điều này có thể dễ dàng là một đối tượng may mắn (và trong mã thực tế của tôi); lập một ví dụ độc lập bằng cách sử dụng phương thức lớp.)

CHỈNH SỬA 2: Chỉ cần điền đầy đủ các nhận xét bên dưới, đây là những gì tôi thực sự đang làm (thư viện đường thuộc tính Moose, được tạo với Moose::Exporter) :

# adds an accessor to a sibling module 
sub foreignTable 
{ 
    my ($meta, $table, %args) = @_; 

    my $class = 'MyApp::Dir1::Dir2::' . $table; 
    my $dbAccessor = lcfirst $table; 

    eval "require $class" or do { die "Can't load $class: [email protected]" }; 

    $meta->add_attribute(
     $table, 
     is => 'ro', 
     isa => $class, 
     init_arg => undef, # don't allow in constructor 
     lazy => 1, 
     predicate => 'has_' . $table, 
     default => sub { 
      my $this = shift; 
      $this->debug("in builder for $class"); 

      ### here's the line that uses a hash value as the method name 
      my @args = ($args{primaryKey} => $this->${\$args{primaryKey}}); 
      push @args, (_dbObject => $this->_dbObject->$dbAccessor) 
       if $args{fkRelationshipExists}; 

      $this->debug("passing these values to $class -> new: @args"); 
      $class->new(@args); 
     }, 
    ); 
} 

Tôi đã thay thế dòng được đánh dấu ở trên bằng điều này:

 my $pk_accessor = $this->meta->find_attribute_by_name($args{primaryKey})->get_read_method_ref; 
     my @args = ($args{primaryKey} => $this->$pk_accessor); 

PS. Tôi đã chỉ nhận thấy rằng kỹ thuật tương tự này (sử dụng lớp meta Moose để tra cứu coderef thay vì giả định quy ước đặt tên) không thể cũng được sử dụng cho các vị từ, vì Class::MOP::Attribute không có truy cập get_predicate_method_ref tương tự. :(

+0

Tôi không nghĩ rằng có thể do để phân tích cú pháp của Perl. Tại sao bạn không muốn sao chép $ hash {func} vào một vô hướng đầu tiên? –

+0

Không có lý do cụ thể ngoại trừ nó có vẻ không cần thiết, và đây là một câu đố thú vị mà stumped tôi. Tôi không tin rằng đơn giản chỉ vì tôi không biết câu trả lời là không có câu trả lời. :) (tl; dr phiên bản: bởi vì tôi tò mò!) – Ether

+0

Er, có vẻ như với tôi rằng nếu bạn đang sử dụng Moose, sau đó bạn vẫn đang đi về nó một cách sai lầm. Một trong những tính năng của Moose là mô hình đối tượng meta được xây dựng trên ... Tôi có cảm giác rằng có một phương pháp bạn có thể gọi để tìm kiếm thực tế theo tên chuỗi, sau đó bạn có thể gọi, thay vì sử dụng các chuỗi trống . Tôi không biết nó ra khỏi đầu của tôi, mặc dù ... –

Trả lời

14
Foo->${\$hash{func}}; 

Nhưng cho rõ ràng, tôi muốn có lẽ vẫn viết nó như:

my $method = $hash{func}; 
Foo->$method; 
+0

Đơn giản * và * hiển nhiên; Tôi thích nó! – Ether

+0

Tôi hiểu dấu đô la đầu tiên. Nhưng những gì tôi không nhận được là dấu gạch chéo ngược. – innaM

+1

@Manni: $ {...} được phân tích cú pháp dưới dạng điều kiện vô hướng thay vì định hướng bởi vì nội dung không phải là chuỗi ký tự. Dấu gạch chéo ngược là tạo tham chiếu đến giá trị của $ hash {func}. –

2

Có một lý do bạn đang lưu trữ tên chương trình con thay vì các tham chiếu đến mã?

ví dụ

use strict; use warnings; 

package Foo; 
sub foo { print "in foo()\n" } 

package main; 
my %hash = (func => \&Foo::foo); 

$hash{func}->(); 

Bạn sẽ không được thông qua tên lớp, nhưng nếu đó là quan trọng với bạn , bạn có thể sử dụng giống như

my %hash = (func => sub { return Foo->foo(@_) }); 
+0

Có, vì tên phụ tương ứng với tên thuộc tính được lấy từ các đối tượng Moose. – Ether

+0

Tôi đã chỉnh sửa câu hỏi của mình để chỉ ra rằng 'Foo' có thể là tên lớp hoặc một đối tượng may mắn. – Ether

+0

Bạn không muốn tham chiếu phụ vì phá vỡ kế thừa. –

1

Các bạn đã thử UNIVERSAL'sthể phương pháp? Bạn sẽ có thể thực hiện một cái gì đó như thế này:

## untested 
if (my $code = $object->can($hash{func})) { 
    $object->$code(); 
} 

tôi đã vô dụng, một dòng ví dụ để chứng minh:

perl -MData::Dumper -le 'my %h = (f => "Dump"); my $o = Data::Dumper->new([qw/1 2 3/]); my $ref = $o->can($h{f}); print $o->$ref()' 
+0

Có, nhưng một lần nữa đây là một sự chuyển hướng khỏi câu hỏi ban đầu của tôi về cách sử dụng giá trị băm như một tên phương thức (mà runrig trả lời). 'can' trong trường hợp này là một giải pháp ít hoàn hảo hơn so với cái tôi đã phác thảo trong một câu hỏi chỉnh sửa, vì nó đưa ra các giả định về việc đặt tên của một trình đọc Moose. – Ether

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