Печать массива в двойных кавычках - PullRequest
5 голосов
/ 05 июля 2011
my @a = (1,2,3,4,5);

print @a;      #output: 12345

print "\n";

print "@a";    #output: 1 2 3 4 5

Печать массива путем помещения его имени в двойные кавычки ставит пробел между значениями каждого индекса на выходе. Как это сделать? Почему print @a; не печатает то же самое? Зачем нужны оба типа? Я имею в виду, когда вы будете использовать print @a; вместо print "@a"; и наоборот.

Ответы [ 5 ]

9 голосов
/ 05 июля 2011

Еще лучший вопрос: почему он не печатает что-то вроде array {0x1232ef} .Предполагается, что для печати выводится строка, а @a не является скаляром.

Черт, даже лучше: это скалярный контекст, так почему бы не напечатать 5, который является количеством элементов вмассив.Вот как:

print scalar @a;

будет печататься.

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

Давайте посмотрим на эту маленькую программу:

@a = qw(a b c d e);

print "@a";         #prints "a b c d e"
print "\n";

print @a;           #prints "abcde"
print "\n";

print @a . "\n";    #prints "5"

print scalar @a;    #prints "5"

Обратите внимание, что print @a печатает abcde, но если я добавлю \n в конце, она напечатает @aв скалярном контексте.

Посмотрите на Perldoc при печати (попробуйте команду perldoc -f print. В большинстве систем вся документация по Perl доступна через perldoc)

* print LIST
* print

Prints a string or a list of strings. Returns true if successful[...]

Ах!Если задан список, будет напечатан список строк.

Текущее значение $, (если есть) печатается между каждым элементом LIST.Текущее значение $ \ (если есть) печатается после того, как был напечатан весь LIST.Поскольку print принимает LIST, все в LIST оценивается в контексте списка, включая любые подпрограммы, чьи списки возврата вы передаете для печати. ​​

Давайте попробуем новую программу:

@a = qw(a b c d e);

$, = "--";
print "@a";         #prints "a b c d e"
print "\n";

print @a;           #prints "a--b--c--d--e"
print "\n";

print @a . "\n";    #prints "5"

print scalar @a;    #prints "5"

Хммм ... $, добавил двойные черточки между элементами списка, но это не повлияло на @a в кавычках.И, если $, упоминается в perldoc, почему все болтают о $"?

Давайте посмотрим на perldoc perlvar

* $LIST_SEPARATOR
* $"

When an array or an array slice is interpolated into a double-quoted string or a
similar context such as /.../ , its elements are separated by this value. Default
is a space. For example, this:

print "The array is: @array\n";

is equivalent to this:

print "The array is: " . join($", @array) . "\n";

Mnemonic: works in double-quoted context.

Итак, это все объясняет!

По умолчанию $" - это один пробел, а по умолчанию $, - ноль.Вот почему мы получили то, что получили!

Еще одна программа ...

@a = qw(a b c d e);

$, = "--";
$" = "++";
print "@a";         #prints "a++b++c++d++e"
print "\n";

print @a;           #prints "a--b--c--d--e"
print "\n";

print @a . "\n";    #prints "5"
print scalar @a;    #prints "5"
9 голосов
/ 05 июля 2011

Когда массив интерполируется в строку, предполагается, что вы можете захотеть визуально различать элементы;когда вы печатаете список, предполагается, что вы просто хотите, чтобы данные выводились непрерывно.Оба настраиваются; $, (по умолчанию '') вставляется между элементами печатаемого списка, тогда как $ " (по умолчанию '') вставляется между элементами массива, интерполированного в строку.

6 голосов
/ 05 июля 2011

В первом случае вы передаете список аргументов print, и каждый из них печатается по очереди.

Во втором случае вы интерполируете массив в строку, а затем печатаетерезультат.Когда массив интерполируется в строку, значения разделяются $", по умолчанию .

1 голос
/ 06 июля 2011

Массив в двойных кавычках

Раздел «Интерполяция массива» документации по perldata объясняет, как туда попадают интеркалированные пробелы в значении "@a":

Массивы и срезы интерполируются в строки в двойных кавычках путем объединения элементов с разделителем, указанным в переменной $" ($LIST_SEPARATOR, если указано use English;), по умолчанию пробел.Следующие значения эквивалентны:

$temp = join($", @ARGV);  # " for benefit of StackOverflow hiliter
system "echo $temp";
system "echo @ARGV";

Это означает, что print "@a" передает одиночный скалярный аргумент print.Напротив, print @a в вашем примере передает пять.

Печать нескольких значений

Документация perlfunc для print объясняет, что print со списком аргументов.

print LIST

… Текущее значение $, (если есть) печатается между каждым элементом LIST.

Документация perlvar для $, является

Handle->output_field_separator( EXPR )
$OUTPUT_FIELD_SEPARATOR
$OFS
$,

Разделитель поля вывода для оператора печати.Если определено, это значение печатается между каждым из аргументов печати.По умолчанию undef.

Мнемоника: что печатается, когда в вашем print выражении есть ,.

Поскольку $, по умолчанию имеет неопределенное значение,вы видите, print выводит свои аргументы без разделителя.В явном виде код вашего вопроса эквивалентен

print join("", @a);

Почему?

Разница в поведении не является особым случаем для print.Массивы интерполируются во все строки в двойных кавычках , как описано выше .Краткий обзор поисков кода Google для print "@..., кажется, показывает, что частое использование print "@foo" отладки вывода, как в

sub foo {
  print "args = @_\n" if $debug;
  ...;
}

Удобный трюк, который МаркDominus использует для предоставления видимых разделителей для списков, значения которых могут содержать пробелы

sub foo {
  if ($debug) {
    local $" = "][";
    print "args = [@_];  # e.g., [foo][1][3.14159]
  }
  ...;
}

Say @a содержит строки вывода, такие как

@a = map "  - $_\n", @error_messages;
print @a;

Вставка неявных пробелов между значениями приведет кмой тщательно сконструированный формат:

- sneaky-sneaky, sir
   - the hideousness of that foot will haunt my dreams forever
    - why would you do that?!

Perl изо всех сил старается сделать то, что мы имеем в виду, даже когда мы не согласны с требованиями, которые мы предъявляем.

1 голос
/ 05 июля 2011

Когда Perl видит массив в интерполированной строке, он переписывает его, используя join:

print "@array";

становится

print join($" => @array);

по умолчанию значение $" равно одному пробелу.

Вы можете настроить это поведение, локализовав изменение на $"

print "@array";     # '1 2 3 4 5'
{
    local $" = '';  # "
    print "@array"; # '12345'
}
print "@array";     # '1 2 3 4 5' 

Вы можете увидеть, как Perl переписывает ваши интерполированные строки, используя опцию -q основного B::Deparse модуля:

$ perl -MO=Deparse,-q -e 'print "@array"'
print join($", @array);
-e syntax OK
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...