Есть ли недостатки в интерполяции в Perl? - PullRequest
12 голосов
/ 17 ноября 2009

Я только начинаю с Perl (буквально сегодня) и читаю бесплатную онлайн-версию Beginning Perl . Ранее в книге упоминалось, что строки в двойных кавычках будут интерполированы. Однако в каждом примере, использующем функцию печати (пока ... я на странице 66), автор передает скалярные переменные в качестве параметра списка. Может быть, я прыгаю из пистолета, и это будет объяснено позже, но есть ли причина выбирать метод A вместо метода B?

Метод А:

$myVar = "value";
print "Current value is ", $myVar, "\n";

Метод B:

$myVar = "value";
print "Current value is $myVar\n";

На мой взгляд, метод B более удобен. Есть ли предпочтительный способ в сообществе? Или, может быть, некоторые скрытые ошибки, которые делают один метод более безопасным для использования по сравнению с другим и т. Д .?

ТИА

Ответы [ 10 ]

14 голосов
/ 17 ноября 2009

Определенно есть скрытые ошибки - perl будет иметь дело с простыми именами переменных и такими выражениями, как

"$array[$subscript]"

и

"$hashref->{key}"

без проблем. Однако по мере того, как ваши выражения становятся все более и более сложными, в конечном итоге perl не сможет определить, где заканчивается ваше выражение и начинается остальная часть вашей строки.

В этой статье много подробностей Переменная интерполяция в двойных кавычках (изначально здесь , но сейчас нет)

12 голосов
/ 17 ноября 2009

Есть несколько вещей, на которые следует обратить внимание при интерполяции, хотя, узнав о них, вы вряд ли когда-нибудь сделаете это по ошибке.

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

  my $p = 'p';
  print "Mind your $ps and qs\n";  # $ps, not $p

  print "Mind your ${p}s and qs";  # now its $p

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

  my $p = 'p';
  print "Mind your $p's and q's\n";  # $p::s, not $p

  print "Mind your ${p}'s and q's";  # now its $p

Perl также может интерполировать доступ к одному элементу к хэшам и массивам, поэтому размещение индексных символов рядом с именем переменной может привести к нежелательным последствиям:

 print "The values are $string[$foo]\n";  That's the element at index $foo
 print "The values are $string{$foo}\n";  That's the value for the key $foo

Если вам нужен адрес электронной почты в строке, вы можете забыть, что Perl интерполирует массивы. Perl делал это с фатальной ошибкой, если вы не избежали @:

 print "Send me mail at joe@example.com\n";  # interpolates @example

 print "Send me mail at joe\@example.com\n";

Поскольку Perl использует обратную косую черту для экранирования некоторых символов, вам нужно удвоить их, если вы хотите буквальный:

 print "C:\real\tools\for\new\work";      # not what you might expect

 print "C:\\real\\tools\\for\\new\\work"; # kinda ugly, but that's life
 print "C:/real/tools/for/new/work";      # Windows still understands this

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

12 голосов
/ 17 ноября 2009

Есть ' Гоча:

$owner = "John";
$item = "motorcycle".
print "This is $owner's $item.\n";  # Oops, parsed as $owner::s

но вышесказанное можно смело записать как

print "This is ${owner}'s $item.\n";
12 голосов
/ 17 ноября 2009

В простом примере, таком как этот, нет ... но подумайте, было ли $myVar на самом деле чем-то более сложным, таким как глубокая разыменование ссылки на хеш или вызов метода. Некоторые вещи интерполируются внутри строк (большинство ссылок на объекты), но вызовы методов этого не делают. Кроме того, массивы при распечатке напрямую выполняют разные операции, а не интерполируются в строку.

PS. Добро пожаловать в Perl; пожалуйста, наслаждайтесь путешествием! :)

4 голосов
/ 17 ноября 2009

Метод А должен быть:

$myVar = "value";
print 'Current value is ', $myVar, "\n";

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

Однако это микрооптимизация, которая на самом деле не имеет большого значения.

Еще один случай использования метода A, если строка содержит escape-символы, которые вы не хотите использовать для выхода:

$myVar = 12000;
print 'Conversion from $US to $CND: ', $myVar,\n";

В этом случае вы не хотите, чтобы Perl искал переменные $US и $CND, вы просто хотите, чтобы в строке был знак доллара.

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

3 голосов
/ 17 ноября 2009

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

'c:\files\'  #parse error
'c:\files\\' #correct

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

2 голосов
/ 17 ноября 2009

Если вы тянетесь к Perl, то вы ищете самый быстрый способ добиться своей цели. Более того, вам рекомендуется делать это так, как вам больше нравится (отсюда и девиз Perl: TMTOWTDI, есть больше, чем один способ сделать это). Поэтому: какой бы способ вам проще было написать, какой способ, который вы, скорее всего, поймете, когда вернетесь к коду позже, - это способ, которым вы должны это сделать (все остальные вещи, например, получение ожидаемого результата при равенстве ).

Если вы обеспокоены "безопасностью", как вы предлагаете, то узнайте о заражении , которое помогает защитить вас от потенциально вредных данных из внешнего мира.

1 голос
/ 17 ноября 2009

(Вероятно, это должна быть вики сообщества).

Единственная очевидная проблема, которая приходит мне в голову, - это интерполяция массивов. Сравнить

print @arr, "\n";

с

print "@arr\n";

Кроме того, иногда сложные разыменования плохо работают с интерполяцией, но это довольно редко.

0 голосов
/ 18 ноября 2009

Интерполяция является отличным упрощением и экономит время. Но можно зайти слишком далеко.

Вы можете сделать несколько странных вещей с интерполяцией, если хотите.

@foo = 0..10;
print "$foo[2*3]"; # prints 6

А для захватывающей произвольной интерполяции вы можете использовать эту мерзость:

print "@{[ some_function_call('in list context') ]}";

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

use Interpolation;
print "I like $eval{ what_I_like() };

sub what_like_like {
    return 'pie';
}

И многое, многое другое.

Информацию об этом модуле см. В Identity.pm: очень забавный модуль и Интерполяция .

0 голосов
/ 17 ноября 2009

Как аутсайдер Perl, который не знаком ни с какими специфичными для perl редакторами и их возможностями выделения, я голосую за использование одинарных кавычек, когда это возможно. Это делает читателя более понятным, что эта строка не содержит ничего, что будет каким-либо образом интерполировано.

...