2011-09-08 22 views

Trả lời

35

(sub { ... }) sẽ cung cấp cho bạn con trỏ đến chức năng, do đó bạn phải gọi bằng cách tham khảo.

(sub { print "Hello world\n" })->();

Phương pháp dễ dàng khác, như đã chỉ ra bởi Blagovest Buyukliev sẽ được dereference con trỏ hàm và gọi đó là sử dụng { } khai thác

&{ sub { print "Hello World" }}();

+0

Đó nên là '& {tiểu {print "Hello World"}} () '. Không có parens, đó là một cuộc gọi rất đặc biệt. – ikegami

+0

vì vậy ikegami thật - cố định – zellio

+0

@ikegami: ý của bạn là 'một cuộc gọi rất đặc biệt'? Tại sao bạn không thể để lại dấu ngoặc đơn? –

4

Bạn cần mũi tên điều hành:

(sub { print 1;})->(); 
5

Tôi đang không ngừng thích thú bằng cách tìm cách để gọi các chức năng ẩn danh:

$foo = sub {say 1}; 

sub bar {goto $foo}; 
bar; 

''->$foo; # technically a method, along with the lovely: 

undef->$foo; 

() = sort $foo 1,1; # if you have only two arguments 

và, tất nhiên, hiển nhiên:

&$foo(); 
$foo->(); 
11

Không cần nhiều Perl để gọi một chương trình con ẩn danh mà nó được định nghĩa. Nói chung, bạn có thể đạt được bất kỳ loại phạm vi bạn cần với các khối trần. Một trường hợp sử dụng mà bạn nghĩ đến là tạo một dãy bí danh:

my $alias = sub {\@_}->(my ($x, $y, $z)); 

$x = $z = 0; 
$y = 1; 

print "@$alias"; # '0 1 0' 

Nếu không, bạn thường sẽ lưu một chương trình con ẩn danh trong cấu trúc dữ liệu hoặc biến. Các phong cách gọi sau đây làm việc với cả một biến và một tuyên bố sub {...}:

dereference arrow: sub {...}->(args) or $code->(args) 

dereference sigil: &{sub {...}}(args) or &$code(args) 

nếu bạn có coderef trong một vô hướng, bạn cũng có thể sử dụng nó như một phương pháp trên các giá trị thường xuyên và may mắn.

my $method = sub {...}; 

$obj->$method   # same as $method->($obj) 
$obj->$method(...)  # $method->($obj, ...) 

[1, 2, 3]->$method  # $method->([1, 2, 3]) 
[1, 2, 3]->$method(...) # $method->([1, 2, 3], ...) 
+1

'sub {} ->()', 'do {}' và '{}' tất cả đều có các thuộc tính khác nhau. Tôi đặt 'sub {} ->()' gần 'do {}', không phải '{}'. – ikegami

22

Yay, tôi không mong các bạn sẽ nghĩ ra nhiều khả năng đó. Nhưng bạn nói đúng, đây là perl và TIMTOWTDI: +1 cho creativitiy!

Nhưng thành thật mà nói, tôi sử dụng hầu như không một hình thức hơn như sau:

Các cơ bản Cú pháp

my $greet = sub { 
    my ($name) = @_; 
    print "Hello $name\n"; 
}; 

# ... 

$greet->('asker') 

Nó khá thẳng về phía trước: sub {} trả về một tham chiếu đến một thói quen phụ, mà bạn có thể lưu trữ và vượt qua xung quanh giống như bất kỳ vô hướng nào khác. Bạn có thể gọi nó bằng dereferencing. Ngoài ra còn có một cú pháp thứ hai để dereference: &{ $sub }('asker'), nhưng cá nhân tôi thích cú pháp mũi tên, bởi vì tôi tìm thấy nó dễ đọc hơn và nó khá nhiều aligns với dereferencing hashes $hash->{ $key } và mảng $array->[ $index ]. Thông tin thêm về tài liệu tham khảo có thể được tìm thấy trong perldoc perlref.

Tôi nghĩ rằng ví dụ được đưa khác là một chút cao, nhưng tại sao không có một cái nhìn vào họ:

Chuyển đến

sub bar {goto $foo}; 
bar; 

Hiếm khi nhìn thấy và nhiều lo sợ những ngày này.Nhưng ít nhất nó là một goto &function, được coi là ít có hại hơn bạn bè quanh co: goto LABEL hoặc goto EXPRESSION (chúng không được chấp nhận kể từ 5,12 và tăng cảnh báo). Có một số trường hợp, khi bạn muốn sử dụng biểu mẫu đó, bởi vì đây không phải là một cuộc gọi hàm bình thường. Chức năng gọi (bar trong ví dụ đã cho) sẽ không xuất hiện trong ngăn xếp cuộc gọi. Và bạn không vượt qua các thông số của mình, nhưng hiện tại @_ sẽ được sử dụng. Có một cái nhìn lúc này:

use Carp qw(cluck); 

my $cluck = sub { 
    my ($message) = @_; 
    cluck $message . "\n"; 
}; 


sub invisible { 
    @_ = ('fake'); 
    goto $cluck; 
} 

invisible('real'); 

Output:

fake at bar.pl line 5 
    main::__ANON__('fake') called at bar.pl line 14 

Và không có gợi ý của một chức năng vô hình trong stack trace. Thông tin thêm về goto trong perldoc -f goto.

Phương pháp Calls

''->$foo; 
# or 
undef->$foo; 

Nếu bạn gọi một phương thức trên một đối tượng, tham số đầu tiên truyền cho phương pháp đó sẽ là invocant (thường là một ví dụ hoặc tên lớp). Tôi đã nói rằng TIMTOWTCallAFunction?

# this is just a normal named sub 
sub ask { 
    my ($name, $question) = @_; 
    print "$question, $name?\n"; 
}; 

my $ask = \&ask; # lets take a reference to that sub 

my $question = "What's up"; 

'asker'->ask($question); # 1: doesn't work 

my $meth_name = 'ask'; 
'asker'->$meth_name($question); # 2: doesn't work either 

'asker'->$ask($question); # 1: this works 

Trong đoạn trên là hai cuộc gọi, mà sẽ không làm việc, bởi vì perl sẽ cố gắng tìm một phương pháp gọi là ask trong gói asker (trên thực tế nó có thể làm việc nếu mã đó là trong gói nói). Nhưng thứ ba thành công, bởi vì bạn đã cung cấp cho perl phương pháp đúng và nó không cần phải tìm kiếm nó. Như thường lệ: thêm thông tin trong số perldoc Tôi không thể tìm thấy bất kỳ lý do nào ngay bây giờ, để tha thứ điều này trong mã sản xuất.

Kết luận

Ban đầu tôi không có ý định viết rằng có rất nhiều, nhưng tôi nghĩ điều quan trọng là phải có các giải pháp chung vào đầu của một câu trả lời và một số giải thích cho các cấu trúc bất thường. Tôi thừa nhận là loại ích kỷ ở đây: Mỗi người trong chúng ta có thể kết thúc duy trì mã số một ai đó, người đã tìm thấy câu hỏi này và chỉ cần sao chép ví dụ trên cùng.

+3

+1 cho can đảm; bất cứ khi nào tôi dành thời gian để viết những câu trả lời như thế này, tôi bị những chiếc xe tải đổ nát có chứa ... quá dài .. hoặc ..nobody muốn dành nhiều thời gian để đọc điều này ... vì vậy, tôi sẽ đặt trong +1 này chỉ trong trường hợp bạn bị xe tải đâm trúng. (và bất kỳ ai khác đã làm như vậy) – osirisgothra

+1

@osirisgothra cảm ơn vì những lời tốt đẹp. câu trả lời là gần bốn tuổi - và không có xe tải cho đến nay: -D –

+2

Các lập trình viên không thể bị làm phiền khi đọc là lười biếng theo cách xấu, không phải là cách tốt.Về cơ bản, chúng không xa công việc "làm nhà của tôi" cho tôi vì vậy tôi có thể đi đến bãi biển. –

0

Bạn thậm chí có thể không cần một chức năng ẩn danh nếu bạn muốn chạy một khối mã và có số không hoặc một đầu vào. Thay vào đó, bạn có thể sử dụng map.

Chỉ cần cho các tác dụng phụ:

map { print 1 } 1; 

Chuyển đổi dữ liệu, chăm sóc để gán cho một danh sách:

my ($data) = map { $_ * $_ } 2; 
Các vấn đề liên quan