2010-08-22 66 views
11

Tôi đã làm việc với perl trong khoảng hai tháng nay; nó chỉ xảy ra với tôi rằng tôi không biết làm thế nào để thiết lập các đối số mặc định cho các chương trình con. Dưới đây là những gì tôi đã xem xét:Giá trị đối số mặc định trong chương trình con

sub hello { 
    print @_ || "Hello world"; 
} 

Và nó hoạt động tốt nếu tất cả những gì bạn cần là một đối số. Bạn sẽ đặt giá trị mặc định cho nhiều đối số như thế nào? Tôi sẽ làm điều này:

sub hello { 
    my $say = $_[0] || "Hello"; 
    my $to = $_[1] || "World!"; 
    print "$say $to"; 
} 

Nhưng đó là rất nhiều công việc ... Phải có một cách dễ dàng hơn; có thể là một thực hành tốt nhất? Cảm ơn!

Trả lời

2

Có mô-đun Attribute::Default trên CPAN. Có lẽ sạch hơn điều này, và tránh một vài phức tạp (chẳng hạn như, nếu bạn muốn vượt qua false cho chương trình con của bạn?).

Tôi cũng thấy mọi người sử dụng my $var = exists @_[0] ? shift : "Default_Value";, nhưng tài liệu của Perl ghi chú rằng calling exists on arrays is deprecated, vì vậy tôi sẽ không thực sự khuyên bạn nên sử dụng nó.

Snippet của Attribute::Default từ trang doc:

sub vitals : Default({age => 14, sex => 'male'}) { 
    my %vitals = @_; 
    print "I'm $vitals{'sex'}, $vitals{'age'} years old, and am from $vitals{'location'}\n"; 
    } 

    # Prints "I'm male, 14 years old, and am from Schenectady" 
    vitals(location => 'Schenectady'); 
11

Tôi thường làm điều gì đó như:

sub hello { 
    my ($say,$to) = @_; 
    $say ||= "Hello"; 
    $to ||= "World!"; 
    print "$say $to\n"; 
} 

Lưu ý rằng bắt đầu từ perl 5.10, bạn có thể sử dụng "//=" nhà điều hành để kiểm tra nếu biến được xác định và không chỉ khác 0. (Hãy tưởng tượng cuộc gọi hello("0","friend"), mà sử dụng ở trên sẽ mang lại "Hello friend", có thể không phải là những gì bạn muốn. Sử dụng toán tử //= nó sẽ mang lại "0 friend").

+0

Yea tôi đã cố gắng 'in @_ // "Hello world";' nhưng tôi đã nhận '0' ... – David

+3

@Davidmoreen: kiểm tra mảng để xác định không hữu ích – ysth

+3

@Davidmoreen, cách chính xác để nói đó là 'in $ _ [0] //" Hello world ";'. Như bạn đã nói, bạn không thể sử dụng 'đã định nghĩa' trên một mảng (nghĩa là' // 'có nghĩa là), bởi vì một mảng trong ngữ cảnh vô hướng trả về độ dài của nó, mà luôn luôn được định nghĩa. – cjm

4

Bởi vì cơ chế của Perl để chuyển đối số cho các chương trình con là một danh sách duy nhất, các đối số là vị trí. Điều này gây khó khăn cho việc cung cấp các giá trị mặc định. Một số tích hợp sẵn (ví dụ: substr) xử lý việc này bằng cách sắp xếp các đối số theo khả năng chúng được sử dụng - các đối số ít được sử dụng hơn xuất hiện ở cuối và có các giá trị mặc định hữu ích.

Cách sạch hơn để thực hiện việc này là sử dụng đối số được đặt tên. Perl không hỗ trợ đối số tên cho mỗi gia nhập, nhưng bạn có thể bắt chước họ với băm:

use 5.010; # for // 

sub hello { 
    my %arg = @_; 
    my $say = delete $arg{say} // 'Hello'; 
    my $to = delete $arg{to} // 'World!'; 
    print "$say $to\n"; 
} 

hello(say => 'Hi', to => 'everyone'); # Hi everyone 
hello(say => 'Hi');     # Hi world! 
hello(to => 'neighbor Bob');   # Hello neighbor Bob 
hello();        # Hello world! 

Lưu ý: Các định nghĩa-hoặc điều hành // đã được bổ sung trong Perl v5.10. Nó mạnh mẽ hơn so với sử dụng lôgic hoặc (||) vì nó sẽ không mặc định trên các giá trị sai về mặt logic hợp lý ''0.

14

tôi làm điều đó với các đối số được đặt tên như vậy:

sub hello { 
    my (%arg) = (
     'foo' => 'default_foo', 
     'bar' => 'default_bar', 
     @_ 
    ); 

} 

Tôi tin Params::Validate hỗ trợ giá trị mặc định, nhưng đó là nhiều rắc rối hơn tôi muốn lấy.

3

Nếu bạn thấy tài liệu của Perl Thực tiễn tốt nhất: Mặc định luận Values ​​ bởi Damian Conway sau đó bạn sẽ tìm thấy một số điểm quan trọng như:

  • giải quyết bất kỳ tranh cãi mặc định giá trị càng sớm vì @_ được giải nén.
  • Nó gợi ý rằng nếu bạn có nhiều giá trị mặc định để thiết lập thì cách sạch nhất sẽ được tính ra các giá trị mặc định là thành bảng, băm và sau đó khởi tạo băm đối số với bảng đó.

Ví dụ:

#!/usr/bin/perl 
    use strict; 
    use warning; 
    my %myhash = (say => "Hello", to => "Stack Overflow"); 
    sub hello { 
    my ($say, $to) = @_; 
    $say = $say ? $say : $myhash{say}; 
    $to = $to ? $to : $myhash{to}; 
    print "$say $to\n"; 
    } 
    hello('Perl');  # output :Perl Stack Overflow 
    hello('','SO');  # output :Hello SO 
    hello('Perl','SO'); # output :Perl SO 
    hello();   # output :Hello Stack Overflow 

Để cụ thể hơn và ví dụ hoàn chỉnh tham khảo Perl Best Practices.

4

Ngoài ra, hãy xem Method::Signatures. Điều này sử dụng Devel::Declare để cung cấp thêm một số đường (cần thiết!) Với các từ khóa methodfunc.

Dưới là ví dụ của bạn bằng cách sử dụng mới func:

use Method::Signatures; 

func hello ($say='Hello', $to='World!') { 
    say "$say $to"; 
} 

hello('Hello', 'you!'); # => "Hello you!" 
hello('Yo');    # => "Yo World!" 
hello();      # => "Hello World!" 

/I3az/

1

Cách tốt nhất để giải quyết vấn đề của bạn đã được trình bày trong các câu trả lời khác.
Một điều mà cuộc đình tôi mặc dù là bạn nói rằng:

sub hello { 
    print @_ || "Hello world"; 
} 

Và đó hoạt động tốt vì nếu tất cả các bạn cần là một cuộc tranh cãi.

Bạn đã thực sự thử mã đó chưa? Nó sẽ in số lượng đối số hoặc khi không có đối số nào được cung cấp, Hello World!
Lý do cho điều này là || -operator được ưu tiên và buộc phía bên trái trong ngữ cảnh vô hướng, do đó giảm @_ xuống số đối số bạn cung cấp, KHÔNG phải chính đối số!
có một cái nhìn tại perlop để biết thêm thông tin về các toán tử trong Perl.

HTH,
Paul

0

Đối với đường nhiều hơn, xem thêm Method::Signatures:

func add($this = 23, $that = 42) { 
    return $this + $that; 
} 
+0

Rất tiếc, không nhận thấy nó đã được đề xuất – pwes

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