Perl 中 “ 和 ' 的区别

The difference between " and ' in Perl

提问人:Eugen Konkov 提问时间:5/23/2019 最后编辑:EmmaEugen Konkov 更新时间:5/24/2019 访问量:498

问:

根据评论:

也不应在 中使用单引号。 相反,请尝试:print ">>${ '_<$filename' }<<\n"print ">>${ \"_<$filename\" }<<\n"

我一直认为 和 之间的区别只是字符串是否被解释。"'

我想问为什么在这种情况下:

print ">>${ \"_<$filename\" }<<\n"
print ">>${  '_<$filename'  }<<\n"

Perl 打印不同的值?

为什么我应该使用而不是在这里?\"'

字符串 perl 引号

评论

1赞 Håkon Hægland 5/23/2019
我的猜测是,这是因为被解析了两次。如果你在里面使用单引号,它不会插值(因为单引号不会插值)?"${ \"_<$filename\" }"$filename

答:

2赞 Dada 5/23/2019 #1

在这两种情况下,都不是由外部字符串 () 插值,而是由 插值。(这只是从行为中扣除的)。这意味着 在 中,根本不是插值,而 是 。$filename">>...<<\n"${ ... }">>${ '_<$filename' }<<\n"$filename">>${ \"_<$filename\" }<<\n"

如果它是由外部字符串插值的,那么如果你的字符串包含引号,你就会遇到一些麻烦:

$filename = "ab'cd";

如果插值是由外部字符串完成的,则等价于 ,这是一个语法错误。或者更确切地说,是 ,它等价于 ;也不是你想要的。"${'$filename'}""${'ab'cd'}""${ab'cd}""${ab::cd}"

而如果插值是由 完成的,那么 in 是 真的(没有转义的双引号),它插值 ,你会得到类似 的东西,就像你想要的那样。${}"${'$filename'}"${...}${"$filename"}$filename${"ab'cd"}


请看这个例子:

$abcd = "First var";
${'$v'} = "Second var";
$v = "abcd";

say "${\"$v\"}"; # prints "First var"
say "${'$v'}";   # prints "Second var"

它表明 with 是插值的,而 with 则不是。"${\"$v\"}"$v"${'$v'}"

评论

0赞 Eugen Konkov 5/23/2019
的值是$filenameSpecio::Constraint::Simple->_optimized_constraint
0赞 Dada 5/23/2019
@EugenKonkov没关系:我的例子说明了为什么插值需要由 而不是 .对于Perl来说,查看其值并据此决定需要在哪里进行插值是荒谬的。${}""$filename
0赞 Eugen Konkov 5/23/2019
现在这个例子回答了这个问题。这是否记录了双引号字符串中的单引号切换插值?
0赞 Dada 5/23/2019
@EugenKonkov我在 perldata 和 perlop 中都没有找到任何关于此的文档。我不知道它是否在任何地方都有记录。
0赞 Eugen Konkov 5/23/2019 #2

这只是我的假设,我找不到任何关于此的官方文档,但似乎有效。

还说我应该:ilmarigo via the symbol table

${$main::{'_<foo::bar::baz'}}

因此,我的代码分为两种情况:。

案例一:

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

案例二:

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'} } );

此外,无论它如何引用,它都有。只需通过符号表,我就可以达到以下值:

SV = PV(0x15e0a40) at 0x186cd10
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x1934880 "Specio::Constraint::Simple->_optimized_constraint"\0
  CUR = 49
  LEN = 51

发现
它无论如何引用变量名称。唯一的区别在于我们如何去:

  1. 直接
  2. VIA 符号表

因此,如果变量名称没有双冒号,则可以使用以下任一形式:

    Devel::Peek::Dump( ${ $::{ "$name" } } );
    Devel::Peek::Dump( ${    "::$name"   } );

两者都会引用同一件事。

但是,如果变量名称包含双冒号,则只能通过符号表访问其值

UPD:
有些人可能会注意到,这个答案并没有直接回答我的问题。你是对的。 我在这里发布了两种不同方法的访问变量值的测试结果,因为我认为这些发现很重要。

评论

1赞 Dada 5/23/2019
虽然这很有趣,但我不明白它如何回答你的问题,这归结为字符串内 a 之间和内部的区别。在答案的所有示例中,您都使用双引号将 括起来。\"_<$filename\"'_<$filename'${}$filename
2赞 Dada 5/23/2019
也许这应该是你之前问题的答案?
0赞 Eugen Konkov 5/24/2019
@Dada:并非所有示例都有 file 名。注意硬编码:'Devel::Peek::Dump( ${ '::_<Specio::Constraint::Simple->_optimized_constraint' } );
0赞 Eugen Konkov 5/24/2019
@Dada:我同意这不能直接回答我的问题。这里我展示的是 的一些方面的测试结果。我不会接受这个答案。不用担心。${ }
6赞 TFBW 5/23/2019 #3

对你的问题的简短回答是在你的第一个例子中插入的,而在第二个例子中没有。你问为什么?天啊。系好安全带,享受颠簸的旅程。$filename

首先,了解符号的用途。使用它有两个原因:一是简单地将变量名称与周围的文本区分开来;另一种是取消引用 BLOCK(代码)返回的值。${...}

如果括号的内容只是一个裸词(可能带有空格),那么它只是一个简单的变量名称。因此,字符串、字符串和字符串都产生相同的结果。如果您需要在字符串中的变量之后直接附加文本,这将非常方便:而不是说 ,您可以说 。这些符号在插值字符串之外也起作用:如果你愿意,你可以说。"$foo""${foo}""${ foo }"$foo.'bar'"${foo}bar"${foo} = 'bar'

但这不是你的代码正在做的事情。哦不。你把象征性去引用的双管霰弹枪直接对准你的脚。您将括号的内容作为代码进行评估,并将结果用作对变量的引用。你把整个地段放在一个插值字符串中,使它加倍混乱。我们不要对取消引用的概念进行深入讨论,因为这不是这里的主要问题。关键的一点是,如果大括号中的内容不是裸词,那么它实际上正在被评估。

现在,要明白,当 Perl 到达插值字符串中的“${”符号时,它必须决定它在这里插值的内容:一个普通的变量名称或代码。在不插入任何其他内容的情况下,它寻求匹配的右括号。如果由这些括号分隔的子字符串看起来不像一个裸词,那么它将被计算。您仍然需要在此区域中转义双引号,因为任何未转义的双引号都将计为作为其子集的外部字符串的最终分隔符,而“块”的其余部分将位于字符串之外。

考虑到这一点,我们可以看到你的第一个示例 evals ,而你的第二个示例 evals 。这就是插值字符串与非插值字符串之间的区别:第一个被某物替换,而第二个是严格意义上的字面意思。"_<$filename"'_<$filename'$filename

在这两种情况下,字符串都用于对具有可怕名称的全局标量变量执行符号取消引用,如果您实际定义了它,您将感到羞耻。说得越少越好。

如果您认为我在开玩笑说大括号的内容被有效评估,请尝试此代码。

print "This, ${die qq(oops!\n)}, and this.\n";

当然,像这样的字符串内代码和 proper 之间的主要区别在于,它会捕获异常并设置 $@。这不会:它只是像在普通代码块中一样死亡。eval()eval()

这就产生了 Perl 的一个隐藏技巧。您不能像 一样插值方法调用,但可以取消引用包含它的数组的引用,如下所示。$foo->bar

print "@{[$foo->bar]}\n";

总而言之,为了上帝的爱,请不要那样写代码。

3赞 ikegami 5/24/2019 #4

答案很简单:当在字符串文字的代码中找到 A 和 character 时,没有特别的意义。$@

">>${ \"_<$filename\" }<<\n"等效于 。">>" . ${ "_<$filename" } . "<<\n"

">>${ '_<$filename'" }<<\n"等效于 。">>" . ${ '_<$filename' } . "<<\n"

如您所见,没有替换为 的值,这在双引号字符串中通常会发生。$filename$filename

如果这还不清楚,让我们考虑一个更常见的例子。

">>$h{$key}<<"等效于 。">>" . $h{$key} . "<<"

">>$h{\"$key\"}<<"等效于 。">>" . $h{"$key"} . "<<"

">>$h{'$key'}<<"等效于 。">>" . $h{'$key'} . "<<"

现在考虑一下如果改为插值会发生什么。(例如,使用 .)这种行为将更加出乎意料,也更加危险。$key$key = "2+3";


同样,当在字符串文本的代码中找到字符时,除非它转义了分隔符,否则它没有特殊意义。\

"foo ${\f()} bar"相当于"foo " . ${\f()} . " bar"

如您所见,没有像通常在双引号字符串文本中那样替换为表单提要。\f