2010-08-22 4 views
11

Я работаю с perl около двух месяцев; мне просто пришло в голову, что я не знаю, как устанавливать аргументы по умолчанию для подпрограмм. Вот что я рассмотрел:Значения аргументов по умолчанию в подпрограммах

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

И это отлично работает, если все, что вам нужно, было одним из аргументов. Как бы вы установили значения по умолчанию для нескольких аргументов? Я собирался сделать это:

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

Но это очень много работы ... Должен быть более простой способ; возможно, лучшая практика? Благодаря!

ответ

2

В CPAN имеется модуль Attribute::Default. Наверное, чище, чем это, и избегает нескольких сложностей (например, что, если вы хотите передать false в свою подпрограмму?).

Я также видел, как люди используют my $var = exists @_[0] ? shift : "Default_Value";, но документация Perl отмечает, что calling exists on arrays is deprecated, поэтому я бы не рекомендовал его.

Отрывок из Attribute::Default со страницы док:

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

я обычно делаю что-то вроде:

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

Обратите внимание, что начиная с Perl 5.10, вы можете использовать "//=" оператора, чтобы проверить, если переменная определена, а не просто отлична от нуля. (Предположим, что вызов hello("0","friend"), который с использованием вышеизложенного даст "Hello friend", что может быть не так, как вы хотели. Используя оператор //=, он даст "0 friend").

+0

Да я попробовал 'печать @_ // "Hello World",' но я '0 '... – David

+3

@ Davidmoreen: тестирование массива для определения нецелесообразно – ysth

+3

@ Davidmoreen, правильный способ сказать, что это 'print $ _ [0] //« Hello world »;'. Как сказал ysth, вы не можете использовать 'defined' в массиве (что означает' // '), потому что массив в скалярном контексте возвращает свою длину, которая всегда определяется. – cjm

4

Поскольку механизм передачи аргументов в подпрограммы Perl является единственным списком, аргументы являются позиционными. Это затрудняет предоставление значений по умолчанию. Некоторые встроенные модули (например, substr) обрабатывают это путем упорядочивания аргументов в зависимости от того, насколько они вероятны для использования - менее часто используемые аргументы появляются в конце и имеют полезные значения по умолчанию.

Более чистый способ сделать это - использовать именованные аргументы. Perl не поддерживает именованные аргументы по себе, но вы можете подражать их хэш:

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! 

Примечания: Определенный или оператор // был добавлен в Perl v5.10. Он более надежный, чем использование логического или (||), поскольку он не будет устанавливать значения по логически ложным значениям '' и 0.

14

Я делаю это с именованными аргументами вроде так:

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

} 

Я считаю, что Params::Validate поддерживает значения по умолчанию, но это больше проблем, чем я люблю брать.

3

Если вы смотрите документацию Perl Best Practices: По умолчанию аргумент Ценности по Damian Conway, то вы найдете некоторые важные моменты, как:

  • Устраните любые по умолчанию аргумент значения как только поскольку @_ распаковывается.
  • Предполагает, что если у вас есть множество значений по умолчанию, то самый чистый способ будет разложить значения по умолчанию в таблицы, т. Е. Хеш, а затем прединициализировать хэш хэша с этой таблицей.

Пример:

#!/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 

Более подробно и полный пример см Perl Best Practices.

4

Также посмотрите на Method::Signatures. Это использует Devel::Declare, чтобы предоставить дополнительный (необходимый!) Сахар с ключевыми словами method и func.

Ниже ваш пример использования нового 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

Лучший способ для решения вашей проблемы обсуждались в других ответах.
Одна вещь, которая поражает меня, хотя в том, что вы утверждаете, что:

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

И это прекрасно работает, если все, что вам нужно было один аргумент.

Вы действительно пробовали этот код? Он напечатает количество аргументов или, если их не будет, Hello World!
Причина этого в том, что || -оператор имеет приоритет и заставляет левую сторону в скалярном контексте, тем самым уменьшая @_ до количества аргументов, которые вы предоставляете, а не самих аргументов!
посмотрите на perlop для получения дополнительной информации об операторе на Perl.

НТН,
Пол

0

Для больше сахара, смотри также Method::Signatures:

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

Извините, не заметил, что уже было предложено – pwes

Смежные вопросы