2017-02-03 3 views
1

Я хочу написать подпрограмму Perl, как это:

use List::MoreUtils qw{pairwise}; 
sub multiply { 
    my ($a, $b) = @_; 
    return [ pairwise {$a * $b} @$a, @$b ]; 
} 

(умножение просто Например, я собираюсь сделать что-то еще)

Однако это дает мне бессмысленные результаты, потому что Perl запутывается и пытается использовать внешние $a и $b вместо элементов списка.

Если я пытаюсь этот код в REPL (например, как reply):

0> use List::MoreUtils qw{pairwise}; 
1> my $a = [1, 2, 3]; 
… 
2> my $b = [3, 2, 1]; 
… 
3> pairwise {$a * $b} @$a, @$b; 
Can't use lexical $a or $b in pairwise code block at reply input line 1. 
4> sort {$a <=> $b} @$a; 
"my $a" used in sort comparison at reply input line 1. 
"my $b" used in sort comparison at reply input line 1. 
$res[2] = [ 
    1, 
    3, 
    2 
] 

До сих пор мое решение было заменяющим my ($a, $b) = @_; с my ($a_, $b_) = @_; (то есть переименованием проблемных переменными).

Есть ли другое решение?

+8

Не вызывайте переменные '$ a' и' $ b', которые являются первыми именами переменных? – Sobrique

ответ

6

Ну, первый раз - $a - это ужасное имя переменной. Зачем ты это делаешь? Отдельные буквы почти всегда являются плохим выбором, и почти все нормально, если это просто итератор или другое простое использование.

Таким образом, решение было бы «не называть их $a и $b».

Я имею в виду, если вы действительно не хотите использовать другое имя:

sub multiply { 
    return [ pairwise { $a * $b } @{$_[0]}, @{$_[1]} ]; 
} 

Но то, что вы сделали действительно подчеркнул, почему пространство имен столкновения это плохая идея, и, таким образом, используя $a и $b в вашем коде, поскольку фактические переменные задают проблемы.

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

Я имею в виду, что-то вроде этого должны работы:

sub multiply { 
    my ($a, $b) = @_; 
    return [ pairwise { $::a * $::b } @$a, @$b ]; 
} 

Потому что тогда вы явно с помощью пакета $a и $b не лексических один. Но обратите внимание - это не будет работать одинаково, если они будут импортированы из другого пакета, и это, как правило, становится беспорядочным.

Но это довольно грязно. perlvar говорит вам прямо, что вы не должны делать это:

$ в

$ б

Специальные переменные пакета при использовании рода(), см рода. Из-за этой специфичности $ a и $ b не нужно объявлять (используя использование vars или our()) даже при использовании строгой прагмы vars. Не лексиализуйте их с помощью $ a или my $ b, если вы хотите использовать их в блоке или функции сравнения sort().

И вот до того, как вы попадаете на территорию «имен переменных с одной буквой, это почти всегда плохая идея».

Так серьезно. Есть ли:

my ($first, $second) = @_; 

На самом деле так плохо?

+3

'$ a' не является супер-глобальным, как' $ _', поэтому '$ :: a' будет работать, только если вызов' pairwise' находится в 'main'. Тест: 'perl -MData :: Dumper -we'package Pkg; используйте Data :: Dumper; используйте List :: MoreUtils qw {pairwise}; sub multiply { my ($ a, $ b) = @_; return [попарно {$ :: a * $ :: b} @ $ a, @ $ b]; } print (Dumper (умножить ([2,3,4], [4,3,2]))); '' – ikegami

3

pairwise устанавливает $a10 и $b, найденные в его пакете вызывающего абонента, поэтому вы можете использовать полностью квалифицированные имена переменных.

Предполагая, что этот код находится в пакете main,

use List::MoreUtils qw{pairwise}; 
sub multiply { 
    my ($a, $b) = @_; 
    return [ pairwise { $main::a * $main::b } @$a, @$b ]; 
} 

В качестве альтернативы, our создает лексическую переменную, которая является псевдонимом для переменной текущего пакета с тем же именем, и он отменит my декларацию, так как выдается самое последнее объявление лексической переменной.

use List::MoreUtils qw{pairwise}; 
sub multiply { 
    my ($a, $b) = @_; 
    return [ pairwise { our $a * our $b } @$a, @$b ]; 
} 

Второй подход, очевидно, гораздо менее хрупким, чем первый, но вы знаете, что будет еще менее хрупкими? Не объявляя $a и $b как лексические вары в первую очередь! :) Было бы намного проще использовать разные переменные. Даже $A и $B или $x и $y было бы лучше.

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