Как использовать локальные * на ссылочные аргументы? - PullRequest
2 голосов
/ 07 ноября 2011

Этот вопрос относится к последнему пункту пункта 46 в Эффективное программирование на Perl .

Я протестировал эту функцию, которая позволяет передавать ссылки на массивы, но обращаться к ним как к локальным массивам:

use strict;
sub max_v_local {
    local ( *a, *b ) = @_;
    my $n = @a > @b ? @a : @b;
    my @result;
    for ( my $i = 0 ; $i < $n ; $i++ ) {
        push @result, $a[$i] > $b[$i] ? $a[$i] : $b[$i];
    }
    @result;
}

Но я получаю следующие ошибки, если не использую strict:

Variable "@a" is not imported
Variable "@b" is not imported
Global symbol "@a" requires explicit package name
Global symbol "@b" requires explicit package name

Есть ли способ сделать это с strict?

Обновление

Дальнейшая предыстория. Вышеуказанная подпрограмма была уточнением следующего. Подпрограмма принимает 2 arrayrefs, но использование arrayrefs в подпрограмме может привести к путанице. Приведенный выше код, вероятно, будет быстрее и более читабельным, поскольку он позволяет вам обращаться к arrayrefs как к локальным массивам.

sub max_v {
    my ( $a, $b ) = @_;
    my $n = @$a > @$b ? @$a : @$b; # no. of items
    my @result;
    for ( my $i = 0 ; $i < $n ; $i++ ) {
        push @result, $$a[$i] > $$b[$i] ? $$a[$i] : $$b[$i];
    }
    @result;
}

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

Ответы [ 4 ]

3 голосов
/ 07 ноября 2011

Как упоминает cjm, вам нужно объявить переменные с our (или использовать полные имена).

Теперь несколько советов. Во-первых, назначение из @_ в непроверенный глобус - это немного азартная игра. Я бы написал строку так:

our (@a, @b);
local (*a, *b) = map \@$_ => @_;

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

ref eq 'ARRAY' or die "..." for @_;
our (@a, @b);
local (*a, *b) = @_;
3 голосов
/ 07 ноября 2011

Да.Объявите их с помощью our :

use strict;
sub max_v_local {
    local ( *x, *y ) = @_;
    our (@x, @y);
    my $n = @x > @y ? @x : @y;
    my @result;
    for ( my $i = 0 ; $i < $n ; $i++ ) {
        push @result, $x[$i] > $y[$i] ? $x[$i] : $y[$i];
    }
    @result;
}

(Как правило, не рекомендуется использовать переменные с именем a или b для всего, кроме sort.)

1 голос
/ 07 ноября 2011

Вы хотите использовать переменные пакета @a и @b, поэтому вы хотите использовать нашу .Это почти переменная no strict "vars"; и лексическая область действия.

sub max_v_local {
    local ( *a, *b ) = @_;
    our ( @a, @b );
    ...
}

Но в вашем алгоритме есть проблема.Вы сравниваете элементы более длинного массива с элементами, которые не существуют.Это даст предупреждения и даст неправильный результат для отрицательных значений.Исправление:

sub max_v_local {
    local ( *a, *b ) = @_;
    our ( @a, @b );
    my $n = @a < @b ? @a : @b;
    return
       ( map { $a[$_] > $b[$_] ? $a[$_] : $b[$_] } 0..$n-1 ),
       @a[ @b .. $#a ],
       @b[ @a .. $#b ];
}

Также странно брать ссылки и возвращать список.Возможно, вы захотите вернуть ссылку на массив.(return [ ... ];)

0 голосов
/ 07 ноября 2011

Думаю, это может быть потому, что вы явно не объявили свои переменные @a и @ b

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...