我刚开始使用Perl(字面意思是今天),我正在阅读Beginning Perl的免费在线版本。在早期,该书提到双引号字符串将被插值。但是,在每个使用print函数的例子中(到目前为止......我在第66页左右),作者将标量变量作为列表参数传递。也许我正在跳枪,这将在后面解释,但有没有理由选择方法A而不是方法B?
方法A:
$myVar = "value";
print "Current value is ", $myVar, "\n";
方法B:
$myVar = "value";
print "Current value is $myVar\n";
在我看来,方法B更方便。社区中是否有首选方式?或者也许是一些隐藏的陷阱,使一种方法比其他方法使用更安全。?
TIA
答案 0 :(得分:14)
肯定存在隐藏的陷阱 - perl将处理简单的变量名称和类似
的表达式"$array[$subscript]"
和
"$hashref->{key}"
没有任何问题。但是,随着表达式越来越复杂,最终perl将无法判断表达式停止的位置以及字符串的其余部分是否开始。
本文Variable Interpolation in Double-Quoted Strings(最初为here,但现在还有),有很多血腥的细节
答案 1 :(得分:12)
在一个简单的例子中,没有..但考虑$myVar
实际上是否更复杂,例如深度解引用散列引用或方法调用。有些东西在字符串内插入(大多数对象引用都有),但方法调用没有。当直接打印出来并插入字符串时,数组也可以做不同的事情。
PS。欢迎来到Perl;请享受旅程! :)
答案 2 :(得分:12)
有'
陷阱:
$owner = "John";
$item = "motorcycle".
print "This is $owner's $item.\n"; # Oops, parsed as $owner::s
但上述内容可以安全地写为
print "This is ${owner}'s $item.\n";
答案 3 :(得分:12)
插值有几点需要注意,虽然一旦你了解它们,你几乎不会错误地做它们。
在有效标识符文本旁边放置变量名称。 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插入数组。除非您逃过@
:
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中构造字符串的难易程度。
答案 4 :(得分:4)
方法A应该是:
$myVar = "value";
print 'Current value is ', $myVar, "\n";
当你单引一个字符串时,Perl并不打算阅读整个内容来寻找插值的东西,所以如果你有一个不需要插值的长字符串,使用单引号和附加可能会更快动态部分,如上所述。
然而,这是一种微观优化,并没有真正产生巨大的差异。
使用方法A的另一种情况是,如果字符串包含您不想打扰转义的转义字符:
$myVar = 12000;
print 'Conversion from $US to $CND: ', $myVar,\n";
在这种情况下,您不希望Perl查找$US
和$CND
变量,您只希望字符串中包含美元符号。
最后,这主要是风格问题。我通常会尽量避免使用双引号字符串,除非我需要它们。
答案 5 :(得分:3)
因为我们讨论插值陷阱,所以值得一提的是,如果你使用单引号字符串来避免插值,你仍然需要转义一个尾部斜杠:
'c:\files\' #parse error
'c:\files\\' #correct
这是因为第一个字符串的最后一个字符看起来像是一个转义的单引号,而不是字符串终止符。转义斜杠也将转换为单引号字符串中的单斜杠
答案 6 :(得分:2)
如果您正在寻找Perl,那么您正在寻找最快捷的方式来完成工作。此外,你被鼓励以最像你的思维方式的方式去做(因此Perl的座右铭:TMTOWTDI,有不止一种方式去做)。因此:无论哪种方式更易于编写,以及当您以后回到代码时最有可能理解的方式,都是您应该这样做的方式(所有其他事情,例如给出预期结果,相等) )。
如果您关注“安全”,如您所知,那么请了解tainting,这有助于保护您免受来自外部世界的潜在恶作剧数据。
答案 7 :(得分:1)
(这应该是社区维基。)
我脑海中唯一明显的问题是数组的插值。比较
print @arr, "\n";
与
print "@arr\n";
此外,有时复杂的解除引用不适用于插值,但这些很少见。
答案 8 :(得分:0)
作为Perl局外人,他不熟悉任何特定于Perl的编辑及其强调权力,我会尽可能使用单引号投票。这使得读者更清楚,该字符串不包含任何将以任何方式插值的内容。
答案 9 :(得分:0)
插值是一个很好的简化和节省时间。但是有可能走得太远。
如果你愿意,可以用插值做一些奇怪的事情。
@foo = 0..10;
print "$foo[2*3]"; # prints 6
对于令人兴奋的任意插值,你可以使用这种可憎的:
print "@{[ some_function_call('in list context') ]}";
如果你真的,真的想让内插函数调用工作,那么就有一个模块。查看Interpolation。它可以让你做这样的事情:
use Interpolation;
print "I like $eval{ what_I_like() };
sub what_like_like {
return 'pie';
}
还有更多。
有关此模块的背景信息,请参阅Identity.pm: A Very Funny Module和Interpolation。