2015-04-20 2 views
1

Мне нужно выполнить функцию, которая будет работать как скаляр и массив. Например:Скалярная или массивная функция

@t = testfunc(1, 2, 3, 4); 
$x = testfunc(1, 2, 3, 4); 

У кого-нибудь есть идея, как я могу это сделать? Он должен печатать «скаляр», если это $ x и печатать «массив», если @t. Я пытался сделать что-то вроде этого:

sub testfunc() 
{ 
    print "test"; 
} 

Но даже это не работает:/

+2

Как уже отмечали другие, вы бы использовали 'wantarray' для этого. См. 'Perldoc -f wantarray' http://perldoc.perl.org/functions/wantarray.html – shawnhcorey

+6

Не используйте прототипы (пустые круглые скобки после поднабора). Их использование * только *, чтобы переопределить нормальную функциональность подпрограммы, создать неясные вещи, которые имитируют поведение некоторых встроенных модулей. – TLP

+1

@TLP: если у вас нет 5.20+ и включили экспериментальные подписи (но даже там, '()' в этом случае неприемлемо) – ysth

ответ

4

Эта функция под названием «контекст вызова». Используйте ключевое слово wantarray.

@t = testfunc(1, 2, 3, 4); 
$x = testfunc(1, 2, 3, 4); 
sub testfunc { 
    if (wantarray) { 
     print "List context\n"; 
    } 
    # False, but defined 
    elsif (defined wantarray) { 
     print "Scalar context\n"; 
    } 
    # False and undefined 
    else { 
     print "Void context\n"; 
    } 
} 
4

Там есть функция в Perl называется wantarray, которая возвращает:

  • true если к югу вызывается в контексте списка
  • false если скалярная
  • undef если ни.

В качестве примера:

use strict; 
use warnings; 

sub wantarray_test { 

    if (not defined wantarray()) { 
     print "Called in void context by ", caller(), "\n"; 
    } 
    else { 
     if (wantarray()) { 
      print "Called in list context by ", caller(), "\n"; 
      return ("A", "list", "of", "results"); 
     } 
     else { 
      print "called in a scalar context by ", caller(), "\n"; 
      return "scalar result"; 
     } 
    } 

} 

my @result = wantarray_test(); 
print "@result\n"; 

my $result = wantarray_test(); 
print $result, "\n"; 

wantarray_test(); 

Бонус вопрос:

Как вы думаете, вы получите, если вы:

print wantarray_test(); 

Вы можете сделать даже больше, чем это, если вы так склонны с Contextual::Return - это позволит вам протестировать более подробные контексты, такие как разница между scalar и boolean. (Это полезно, например, если вы хотите протестировать процент - вы можете не хотеть рассматривать «0» как «ложь»).

Но будьте осторожны с контекстно-зависимыми функциями. Очень легко построить какое-то неожиданное поведение, которое может сильно укусить вас за линию.

Как относящаяся к вам нота - вы не должны объявлять свою субстанцию ​​так, как вы. В Perl есть механизм, называемый прототипами, который определяет, какие аргументы вы ожидаете подпрограммой. См.: perlsub. Вы не должны определить свой суб как:

sub testfunc() 
{ 
    # some stuff 
} 

Это указывает прототип, и его следует избегать, если вы не уверены, что это то, что вы хотите.

+4

добавить что-то о плохом прототипе OP – ysth

+0

Хорошая точка. Добавлен. – Sobrique

+0

Ничего себе .. это действительно очень хорошо. Благодаря! Добавив ссылку на это на мой ответ. –

2

Использование wantarray функция

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature 'say'; 

say my $x = testfunc(1,2,3,4); 
say my @x = testfunc(1,2,3,4); 

sub testfunc { 
    return wantarray ? @_ : "@_"; 
} 
1

Странно названный wantarray стандартный подход - это позволяет различать между списком и скалярных контекстов. Вы также можете использовать Want от CPAN, который немного превышает стандартную встроенную функцию wantarray (см. Want documentation).

Ниже следует возвращать те же результаты, как и wantarray решений:

use Want; 
sub testfuncadelic { 
    if (want('LIST')) { 
    rreturn @_; } 
    elsif (want('SCALAR')) { 
    rreturn "@_" ; } 
    return 
} 

Ниже следует вырезать и вставить в оболочку в виде псевдо- «Oneliner» (Unix, синтаксиса), чтобы продемонстрировать:

% cpanm Want 
% perl -MWant -E ' 
sub testfunc { 
if (want("LIST")) { 
    rreturn "array in list context ", @_;} 
elsif (want("SCALAR")) { 
    rreturn "string in scalar context @_"; } 
return } 
$result = testfunc(qw/1 2 3 4/); say $result; 
@results = testfunc(qw/1 2 3 4/); say @results;' 

Выход

string in scalar context 1 2 3 4 
array in list context 1234 

Редактировать

@Sobrique имеет наиболее полное отношение к стандартным подходам здесь - он/она получит мое согласие, если бы я задал вопрос. Одна вещь, которую я пренебрегал выше, это то, что (очевидно, «doh!»), Если wantarray - undef, тогда у вас есть пустое контекст! Возможно, я принял это и не понял, что он может быть использован явно для обнаружения void contxt. Таким образом, wantarray может предоставить вам все три стандартных контекста вызова. Wanted, с другой стороны, о сложном забавном материале, и я не хотел предполагать, что он должен использоваться вместоwantarray. Я все еще думаю, что wantarray должно иметь лучшее имя :-)

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