2012-01-12 32 views
12

Trong mã của tôi, tôi đã sử dụng phương pháp tương đối nguyên thủy của các thông số khai thác từ một cuộc gọi chức năng như sau:Làm thế nào để bạn nhận được nhiều đối số trong các hàm Perl?

sub addSix ($$$$$$) { 
    my ($a, $b, $c, $d, $e, $f) = (shift, shift, shift, shift, shift, shift); 
    return $a + $b + $c + $d + $e + $f; 
} 

print addSix (1, 2, 3, 4, 5, 6) . "\n"; 

(quên mã nguyên thủy, các bit nổi bật là nhiều shift cuộc gọi).

Bây giờ có vẻ khá lộn xộn với tôi và tôi mặc dù Perl có thể có cái gì đó như:

my ($a, $b, $c, $d, $e, $f) = shift (6); 

hoặc một cái gì đó tương tự.

Nhưng tôi không thể tìm thấy bất cứ điều gì như thế. Tôi biết tôi có thể sử dụng mảng cho điều này nhưng tôi nghĩ rằng tôi vẫn sẽ phải giải nén các mảng thành vô hướng cá nhân. Điều đó sẽ không quá tệ đối với trường hợp ví dụ trên, trong đó sáu thông số giống nhau, nhưng tôi quan tâm hơn đến trường hợp chúng không thực sự phù hợp như một mảng.

Làm cách nào để bạn có thể trích xuất các tham số mà không kết thúc bằng một số từ khóa shift?

+0

Lưu ý: Tránh sử dụng '$ a' và' $ b' như tên biến khi chúng được dự định sẽ được sử dụng bên trong 'chỉ khối sort'. – Zaid

+0

@ Zaid, đó là _sample_ mã, tôi thực sự đặt tên biến thực của tôi một chút ngắn gọn hơn :-) – paxdiablo

+2

rõ ràng không phải cho một ví dụ thêm, nhưng đối với một chương trình con thực mà phải mất nhiều hơn một số đối số, nó có thể là tốt nhất để bắt đầu sử dụng các tham số có tên: 'my% params = @_;' và gọi nó là 'mysub foo => 1, bar => 2, baz => 3, ...' –

Trả lời

28

Bạn có thể chỉ cần gõ:

my ($a, $b, $c, $d, $e, $f) = (@_); 

Nếu bạn không có nguyên mẫu đó, và nếu phụ đó đã gọi với hơn sáu lập luận, những người sau khi thứ sáu chỉ đơn giản là "không phù hợp", $f sẽ được đặt thành đối số thứ sáu.

Nếu bạn muốn bắt tất cả các đối số sau ngày thứ sáu, bạn có thể làm như thế này.

my ($a, $b, $c, $d, $e, $f, @others) = (@_); 

Nếu danh sách vô hướng dài hơn danh sách ở bên phải, các thành phần cuối cùng sẽ là undef.

+0

D'Oh. Trong trường hợp vô tình vượt qua mười tham số, '$ f' sẽ là thứ sáu, hoặc kết hợp từ sáu đến mười bằng cách nào đó? Hoặc sẽ ngăn chặn 'phòng ngừa 'vượt qua mười? ... Đừng bận tâm, bản chỉnh sửa "trong bốn phút đầu tiên" của bạn đã làm sáng tỏ điều đó đối với tôi. – paxdiablo

+1

Nguyên mẫu ngăn không cho chuyển bất kỳ điều gì khác hơn sáu đối số. Nếu bạn không có nguyên mẫu danh sách đối số (vì vậy bạn có thể chuyển bất kỳ thứ gì), '$ f' sẽ vẫn là đối số thứ sáu, phần còn lại của danh sách đối số đơn giản là không" khớp ". – Mat

+7

Không cần có '()' xung quanh '@ _' – Zaid

7

Việc sử dụng các nguyên mẫu được khuyến khích cao trừ khi có thực sự cần.

Như mọi khi với Perl, có nhiều cách để thực hiện.

Dưới đây là một cách để đảm bảo chỉ thêm sáu thông số đầu tiên được thông qua:

use List::Util 'sum'; 

sub addSix { sum @_[0..5] } 

Hoặc nếu bạn thích mã tự tài liệu:

sub addSix { 

    my @firstSix = @_[0..5]; # Copy first six elements of @_ 
    return sum @firstSix; 
} 
+1

Tại sao nguyên mẫu được khuyến khích? Tôi đã có thể nghĩ rằng họ là vô giá trong việc phát hiện trường hợp bạn _want_ một số cố định của params. – paxdiablo

+1

@paxdiablo: Tôi sẽ giới thiệu cho bạn [một số đọc ánh sáng] (http://stackoverflow.com/q/297034/133939). Và [sau đó một số] (http://stackoverflow.com/q/3991143/133939). – Zaid

+2

@paxdiablo: ["" Nguyên mẫu không dành cho xác thực đối số "'] (http://stackoverflow.com/a/3991173/133939) – Zaid

3

Tôi nhận ra đây là một chủ đề cũ, nhưng nó đã cho tôi suy nghĩ về một cách tốt hơn để thay đổi nhiều giá trị. Đây là tất cả chỉ là một chút vui vẻ ... Chủ yếu đăng bài này cho các mục đích giáo dục.

Chắc chắn, ($x, $y) = @_ là điều tuyệt vời nếu bạn muốn giữ lại @_, nhưng có lẽ bạn muốn thay đổi đối số của mình vì một số lý do? Có lẽ bạn muốn có bất kỳ chức năng chương trình con bổ sung nào được xác định bởi số đối số còn lại trong @_.

Các sạch một dòng cách tôi có thể nghĩ ra để làm điều này là với một bản đồ đơn giản

sub shiftySub { 
    map { $_ = shift } my ($v, $w, $x, $y); 
    # @_ now has up to 4 items removed 
    if (@_) { ... } # do stuff if arguments remain 
} 
  • Nếu 4 đối số được cung cấp, @_ hiện đang trống trong phạm vi phụ.
  • Nếu 5 đối số được cung cấp, @_ có 1 mục còn lại trong phạm vi phụ.
  • Nếu 3 đối số được cung cấp, @_ trống và $yundef trong phạm vi phụ.

Về shift(6) hành lý thuyết paxdiablo 's, chúng ta có thể tạo ra chức năng riêng của chúng tôi mà thực hiện hoạt động này ...

sub shifter (\@;$) { 
    my ($array, $n) = (@_, 1); 
    splice(@$array, 0, $n); 
} 

Chức năng hoạt động bằng cách thực thi một pass-by-ref nguyên mẫu (một trong những lý do rất hạn chế bạn nên sử dụng nguyên mẫu) để đảm bảo mảng được chuyển trong phạm vi gọi. Sau đó bạn sử dụng nó đơn giản như thế này ...

my @items = ('one', 'two', 'three', 'four'); 
my ($x, $y) = shifter(@items, 2); 
# or as a replacement for shift 
my $z = shifter(@items) 
# @items has 1 item remaining in this scope! 

Tất nhiên, bạn cũng có thể sử dụng chức năng shifter này trong các đăng ký khác của bạn. Nhược điểm chính của một chức năng như thế này là bạn phải theo dõi số lượng bài tập trên cả hai mặt của toán tử.

Tôi hy vọng my $post = 'informative' || 'interesting';

+0

Không phải '||', nhưng trên thực tế '&&'! ;) – cxw

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