Perl 中 " 和 ' 的区别
The difference between " and ' in Perl
根据 this 评论:
You also should not use single quotes in print ">>${ '_<$filename' }<<\n"
.
Instead try: print ">>${ \"_<$filename\" }<<\n"
我一直认为"
和'
之间的区别只是字符串是否被解释。
我想问一下为什么会出现这样的情况:
print ">>${ \"_<$filename\" }<<\n"
print ">>${ '_<$filename' }<<\n"
perl 打印不同的值?
为什么我应该在这里使用 \"
而不是 '
?
发生的情况是,在这两种情况下,$filename
都不是由外部字符串 (">>...<<\n"
) 插入的,而是由 ${ ... }
插入的。 (这只是从行为中推论出来的)。这意味着在 ">>${ '_<$filename' }<<\n"
中,$filename
根本没有插值,而在 ">>${ \"_<$filename\" }<<\n"
.
中
如果它是由外部字符串插入的,那么如果您的字符串包含引号,您会 运行 遇到一些麻烦:
$filename = "ab'cd";
如果插值是由外部字符串完成的,那么"${'$filename'}"
将等同于"${'ab'cd'}"
,这是一个语法错误。或者更确切地说 "${ab'cd}"
,相当于 "${ab::cd}"
;也不是你想要的。
而如果插值是由 ${}
完成的,那么在 "${'$filename'}"
中,${...}
实际上是 ${"$filename"}
(没有转义的 double-quotes),这插入 $filename
,你会得到类似 ${"ab'cd"}
的东西,就像你想要的那样。
考虑这个例子:
$abcd = "First var";
${'$v'} = "Second var";
$v = "abcd";
say "${\"$v\"}"; # prints "First var"
say "${'$v'}"; # prints "Second var"
它表明 "${\"$v\"}"
中插入了 $v
,而 "${'$v'}"
中没有插入。
这只是我的假设,我找不到任何关于此的官方文档,但它似乎可行。
另外 ilmari
说我应该 go via the symbol table
:
${$main::{'_<foo::bar::baz'}}
因此我的代码分为两种情况:.
案例 1:
Devel::Peek::Dump( ${ "::_<$filename" } );
Devel::Peek::Dump( ${ '::_<' ."$filename" } );
Devel::Peek::Dump( ${ "::_<Specio::Constraint::Simple->_optimized_constraint" } );
Devel::Peek::Dump( ${ '::_<Specio::Constraint::Simple->_optimized_constraint' } );
这些都是一样的。双引号或单引号:无所谓。
SV = PV(0xe64ab00) at 0xe300bc8
REFCNT = 1
FLAGS = ()
PV = 0
案例 2:
Devel::Peek::Dump( ${ ${ 'main::' }{ "_<$filename" } } );
Devel::Peek::Dump( ${ ${'::'}{ "_<$filename" } } );
Devel::Peek::Dump( ${ $::{ "_<$filename" } } );
Devel::Peek::Dump( ${ $::{"_<Specio::Constraint::Simple->_optimized_constraint"} } );
Devel::Peek::Dump( ${ $::{'_<Specio::Constraint::Simple->_optimized_constraint'} } );
也不管它是怎么引用的。只需通过符号 table 我可以达到该值:
SV = PV(0x15e0a40) at 0x186cd10
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1934880 "Specio::Constraint::Simple->_optimized_constraint"[=14=]
CUR = 49
LEN = 51
调查结果
它已经不管如何引用变量名了。唯一不同的是我们的方式:
- 直接
- 通过符号 table
因此,如果您的变量名 没有 双冒号,那么您可以使用以下任一形式:
Devel::Peek::Dump( ${ $::{ "$name" } } );
Devel::Peek::Dump( ${ "::$name" } );
两者指的是同一件事。
但是如果你的变量名有双冒号,那么你必须只能通过符号[=]访问它的值 63=]
UPD
有人可能会注意到这个答案并没有直接回答我的问题。你是对的。
我 post 在这里测试了两种访问变量值的不同方法的结果,因为我认为这些发现很重要。
对您的问题的简短回答是 $filename
在您的第一个示例中进行了插值,而在第二个示例中则没有。你为什么问?好家伙。系好安全带,开始颠簸之旅。
首先,了解 ${...}
符号的用途。使用它有两个原因:一个是为了简单地将变量名与周围的文本区分开来;另一种是取消引用 BLOCK(代码)返回的值。
如果括号中的内容只是一个裸词(周围可能有空格),那么它只是一个简单的变量名。因此字符串 "$foo"
和字符串 "${foo}"
以及字符串 "${ foo }"
都产生相同的结果。如果您需要在字符串中的变量后直接附加文本,这会很方便:您可以说 "${foo}bar"
而不是 $foo.'bar'
。这些符号也可以在插入字符串之外使用:如果你愿意,你可以说 ${foo} = 'bar'
。
但这不是您的代码所做的。不好了。您正将 double-barrel 符号取消引用的霰弹枪直接对准您的脚。您将括号中的内容作为代码求值,并将结果用作对变量的引用。你把所有的东西都放在一个内插字符串中,使它变得更加混乱。让我们不要对取消引用的概念进行不必要的深入讨论,因为这不是这里的主要问题。关键是,如果大括号中的内容不是裸词,则它会被有效地求值。
现在,了解当 Perl 到达您的内插字符串中的“${”符号时,它必须决定它在这里内插的是什么:一个普通的变量名或代码。 在不插入任何其他内容的情况下, 它会寻找匹配项 close-bracket。如果由这些括号分隔的 sub-string 看起来不像裸词,那么它将被评估。您仍然需要在该区域转义 double-quotes ,因为任何未转义的双引号都将算作外部字符串的最终定界符,这是其子集,并且 "block" 的其余部分将在字符串。
考虑到这一点,我们可以看到您的第一个示例求值 "_<$filename"
,而您的第二个示例求值 '_<$filename'
。这只是内插字符串与非内插字符串之间的区别:第一个 $filename
被某些东西替换,而第二个是严格的文字。
在这两种情况下,该字符串都用于对名称可怕的全局标量变量执行符号解引用,如果您实际定义了它,那将是您的耻辱。越少说越好
如果您认为我在开玩笑说花括号的内容被有效地求值,请尝试此代码。
print "This, ${die qq(oops!\n)}, and this.\n";
当然,像这样的 in-string 代码与 eval()
的主要区别在于 eval()
会捕获异常并设置 $@。这不会:它只是像在普通代码块中一样死掉。
这引发了 Perl 的隐藏技巧之一。您不能像 $foo->bar
那样插入方法调用,但是您可以取消引用对包含它的数组的引用,就像这样。
print "@{[$foo->bar]}\n";
总而言之,看在上帝的份上,请不要写那样的代码。
答案很简单:$
和 @
字符在字符串文字的代码中没有特殊意义。
">>${ \"_<$filename\" }<<\n"
等同于 ">>" . ${ "_<$filename" } . "<<\n"
.
">>${ '_<$filename'" }<<\n"
等价于 ">>" . ${ '_<$filename' } . "<<\n"
.
如您所见,$filename
并未替换为 $filename
的值,这通常发生在 double-quoted 字符串中。
如果还不清楚,让我们考虑一个更常见的例子。
">>$h{$key}<<"
等价于 ">>" . $h{$key} . "<<"
.
">>$h{\"$key\"}<<"
等同于 ">>" . $h{"$key"} . "<<"
.
">>$h{'$key'}<<"
等同于 ">>" . $h{'$key'} . "<<"
.
现在考虑一下如果 $key
被插值会发生什么。 (例如,使用 $key = "2+3";
。)这种行为会更出乎意料,也更危险。
类似地,\
字符在字符串文字的代码中没有特殊意义,除非它转义了定界符。
"foo ${\f()} bar"
等同于 "foo " . ${\f()} . " bar"
如您所见,\f
没有像 double-quoted 字符串文字中通常发生的那样用换页替换。
根据 this 评论:
You also should not use single quotes in
print ">>${ '_<$filename' }<<\n"
. Instead try:print ">>${ \"_<$filename\" }<<\n"
我一直认为"
和'
之间的区别只是字符串是否被解释。
我想问一下为什么会出现这样的情况:
print ">>${ \"_<$filename\" }<<\n"
print ">>${ '_<$filename' }<<\n"
perl 打印不同的值?
为什么我应该在这里使用 \"
而不是 '
?
发生的情况是,在这两种情况下,$filename
都不是由外部字符串 (">>...<<\n"
) 插入的,而是由 ${ ... }
插入的。 (这只是从行为中推论出来的)。这意味着在 ">>${ '_<$filename' }<<\n"
中,$filename
根本没有插值,而在 ">>${ \"_<$filename\" }<<\n"
.
如果它是由外部字符串插入的,那么如果您的字符串包含引号,您会 运行 遇到一些麻烦:
$filename = "ab'cd";
如果插值是由外部字符串完成的,那么"${'$filename'}"
将等同于"${'ab'cd'}"
,这是一个语法错误。或者更确切地说 "${ab'cd}"
,相当于 "${ab::cd}"
;也不是你想要的。
而如果插值是由 ${}
完成的,那么在 "${'$filename'}"
中,${...}
实际上是 ${"$filename"}
(没有转义的 double-quotes),这插入 $filename
,你会得到类似 ${"ab'cd"}
的东西,就像你想要的那样。
考虑这个例子:
$abcd = "First var";
${'$v'} = "Second var";
$v = "abcd";
say "${\"$v\"}"; # prints "First var"
say "${'$v'}"; # prints "Second var"
它表明 "${\"$v\"}"
中插入了 $v
,而 "${'$v'}"
中没有插入。
这只是我的假设,我找不到任何关于此的官方文档,但它似乎可行。
另外 ilmari
说我应该 go via the symbol table
:
${$main::{'_<foo::bar::baz'}}
因此我的代码分为两种情况:.
案例 1:
Devel::Peek::Dump( ${ "::_<$filename" } );
Devel::Peek::Dump( ${ '::_<' ."$filename" } );
Devel::Peek::Dump( ${ "::_<Specio::Constraint::Simple->_optimized_constraint" } );
Devel::Peek::Dump( ${ '::_<Specio::Constraint::Simple->_optimized_constraint' } );
这些都是一样的。双引号或单引号:无所谓。
SV = PV(0xe64ab00) at 0xe300bc8
REFCNT = 1
FLAGS = ()
PV = 0
案例 2:
Devel::Peek::Dump( ${ ${ 'main::' }{ "_<$filename" } } );
Devel::Peek::Dump( ${ ${'::'}{ "_<$filename" } } );
Devel::Peek::Dump( ${ $::{ "_<$filename" } } );
Devel::Peek::Dump( ${ $::{"_<Specio::Constraint::Simple->_optimized_constraint"} } );
Devel::Peek::Dump( ${ $::{'_<Specio::Constraint::Simple->_optimized_constraint'} } );
也不管它是怎么引用的。只需通过符号 table 我可以达到该值:
SV = PV(0x15e0a40) at 0x186cd10
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1934880 "Specio::Constraint::Simple->_optimized_constraint"[=14=]
CUR = 49
LEN = 51
调查结果
它已经不管如何引用变量名了。唯一不同的是我们的方式:
- 直接
- 通过符号 table
因此,如果您的变量名 没有 双冒号,那么您可以使用以下任一形式:
Devel::Peek::Dump( ${ $::{ "$name" } } );
Devel::Peek::Dump( ${ "::$name" } );
两者指的是同一件事。
但是如果你的变量名有双冒号,那么你必须只能通过符号[=]访问它的值 63=]
UPD
有人可能会注意到这个答案并没有直接回答我的问题。你是对的。
我 post 在这里测试了两种访问变量值的不同方法的结果,因为我认为这些发现很重要。
对您的问题的简短回答是 $filename
在您的第一个示例中进行了插值,而在第二个示例中则没有。你为什么问?好家伙。系好安全带,开始颠簸之旅。
首先,了解 ${...}
符号的用途。使用它有两个原因:一个是为了简单地将变量名与周围的文本区分开来;另一种是取消引用 BLOCK(代码)返回的值。
如果括号中的内容只是一个裸词(周围可能有空格),那么它只是一个简单的变量名。因此字符串 "$foo"
和字符串 "${foo}"
以及字符串 "${ foo }"
都产生相同的结果。如果您需要在字符串中的变量后直接附加文本,这会很方便:您可以说 "${foo}bar"
而不是 $foo.'bar'
。这些符号也可以在插入字符串之外使用:如果你愿意,你可以说 ${foo} = 'bar'
。
但这不是您的代码所做的。不好了。您正将 double-barrel 符号取消引用的霰弹枪直接对准您的脚。您将括号中的内容作为代码求值,并将结果用作对变量的引用。你把所有的东西都放在一个内插字符串中,使它变得更加混乱。让我们不要对取消引用的概念进行不必要的深入讨论,因为这不是这里的主要问题。关键是,如果大括号中的内容不是裸词,则它会被有效地求值。
现在,了解当 Perl 到达您的内插字符串中的“${”符号时,它必须决定它在这里内插的是什么:一个普通的变量名或代码。 在不插入任何其他内容的情况下, 它会寻找匹配项 close-bracket。如果由这些括号分隔的 sub-string 看起来不像裸词,那么它将被评估。您仍然需要在该区域转义 double-quotes ,因为任何未转义的双引号都将算作外部字符串的最终定界符,这是其子集,并且 "block" 的其余部分将在字符串。
考虑到这一点,我们可以看到您的第一个示例求值 "_<$filename"
,而您的第二个示例求值 '_<$filename'
。这只是内插字符串与非内插字符串之间的区别:第一个 $filename
被某些东西替换,而第二个是严格的文字。
在这两种情况下,该字符串都用于对名称可怕的全局标量变量执行符号解引用,如果您实际定义了它,那将是您的耻辱。越少说越好
如果您认为我在开玩笑说花括号的内容被有效地求值,请尝试此代码。
print "This, ${die qq(oops!\n)}, and this.\n";
当然,像这样的 in-string 代码与 eval()
的主要区别在于 eval()
会捕获异常并设置 $@。这不会:它只是像在普通代码块中一样死掉。
这引发了 Perl 的隐藏技巧之一。您不能像 $foo->bar
那样插入方法调用,但是您可以取消引用对包含它的数组的引用,就像这样。
print "@{[$foo->bar]}\n";
总而言之,看在上帝的份上,请不要写那样的代码。
答案很简单:$
和 @
字符在字符串文字的代码中没有特殊意义。
">>${ \"_<$filename\" }<<\n"
等同于 ">>" . ${ "_<$filename" } . "<<\n"
.
">>${ '_<$filename'" }<<\n"
等价于 ">>" . ${ '_<$filename' } . "<<\n"
.
如您所见,$filename
并未替换为 $filename
的值,这通常发生在 double-quoted 字符串中。
如果还不清楚,让我们考虑一个更常见的例子。
">>$h{$key}<<"
等价于 ">>" . $h{$key} . "<<"
.
">>$h{\"$key\"}<<"
等同于 ">>" . $h{"$key"} . "<<"
.
">>$h{'$key'}<<"
等同于 ">>" . $h{'$key'} . "<<"
.
现在考虑一下如果 $key
被插值会发生什么。 (例如,使用 $key = "2+3";
。)这种行为会更出乎意料,也更危险。
类似地,\
字符在字符串文字的代码中没有特殊意义,除非它转义了定界符。
"foo ${\f()} bar"
等同于 "foo " . ${\f()} . " bar"
如您所见,\f
没有像 double-quoted 字符串文字中通常发生的那样用换页替换。