为什么可以通过将尖括号的结果分配给输入记录分隔符来处理文件?

jja*_*jja 6 perl slurp

我知道我可以通过将输入记录分隔符($/)设置为未定义的值来吸引文件,例如

open my $fh, '<', $filename or die "Cannot read from $file: $!";
my $contents = do { local $/; <$fh> };
Run Code Online (Sandbox Code Playgroud)

但是最近我遇到了一个非常相似但又不同的成语:

open my $fh, '<', $filename or die "Cannot read from $file: $!";
my $contents = do { local $/ = <$fh> };
Run Code Online (Sandbox Code Playgroud)

(请注意,local $/ = <$fh>而不是local $/; <$fh>)。

这两种的工作,并且对两者的CPAN实例与分配所述变体所述一个无(尽管后者并不奇怪,更为常见)。

但是我的问题是为什么它起作用?作业的变化形式是什么?

PS:我知道我应该使用例如。File :: Slurper可以吞食文件,但是有时候生活很有趣。

ike*_*ami 4

这是未记录的优化的结果,您不应依赖该优化。


通常LHS = RHS评估如下:

  1. 评估 RHS。
  2. 评估 LHS。
  3. 作业已评估。

正如您所看到的,首先评估赋值的右侧[1]。这允许以下操作:

my $x = 123;

{
   my $x = $x * 2;
   say $x;  # 456
}

say $x;  # 123
Run Code Online (Sandbox Code Playgroud)

显然,在你的案例中发生了一些不同的事情——而且没有记录下来。那是因为LHS = <$fh>很特别。readline( )不是从文件读取然后将结果分配给左侧,而是<>直接写入分配左侧的结果。[2]

  1. 评估 LHS。(这会备份$/并将其设置为undef您的情况。)
  2. $fh被评估。
  3. readline进行求值,直接写入赋值左侧的结果。

不执行任何分配。

此优化没有记录,您不应该依赖它。

local $/ = uc(<$fh>)例如,这是行不通的。


  1. 编译后的代码首先评估右侧:

    $ perl -MO=Concise,-exec -e'$L = $R'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <#> gvsv[*R] s                   <- $R
    4  <#> gvsv[*L] s                   <- $L
    5  <2> sassign vKS/2                <- =
    6  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    
    Run Code Online (Sandbox Code Playgroud)

    下面显示了首先评估的右侧:

    $ perl -e'sub f :lvalue { CORE::say $_[0]; $x } f("L") = f("R")'
    R
    L
    
    Run Code Online (Sandbox Code Playgroud)
  2. $x = uc(<>)uc(<>)先求值$x,然后执行赋值:

    $ perl -MO=Concise,-exec -e'$x = uc(<>)'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <#> gv[*ARGV] s                  \
    4  <1> readline[t3] sK/1             > RHS
    5  <1> uc[t4] sK/1                  /
    6  <#> gvsv[*x] s                   -> LHS
    7  <2> sassign vKS/2
    8  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    
    Run Code Online (Sandbox Code Playgroud)

    $x = uc(<>)评估$xbefore <>,并且它不执行赋值:

    $ perl -MO=Concise,-exec -e'$x = <>'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <#> gvsv[*x] s                   -> LHS
    4  <#> gv[*ARGV] s                  \  RHS
    5  <1> readline[t3] sKS/1           /
    6  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    
    Run Code Online (Sandbox Code Playgroud)

    S请注意旁边的(大写)readline以前不存在。这个“特殊”标志告诉我们readline要写入$x.

    添加local不会改变任何东西。

    $ perl -MO=Concise,-exec -e'local $x = <>'
    1  <0> enter
    2  <;> nextstate(main 1 -e:1) v:{
    3  <#> gvsv[*x] s/LVINTRO
    4  <#> gv[*ARGV] s
    5  <1> readline[t3] sKS/1
    6  <@> leave[1 ref] vKP/REFC
    -e syntax OK
    
    Run Code Online (Sandbox Code Playgroud)