Perl 6的eof太快放弃了吗?

时间:2017-11-01 01:04:37

标签: perl6 filehandle

在Perl 5中,我可以检查标准输入是否打开并从中读取一行。

onOpen

当我运行它时,输入一行输入,它会读取该行并在继续之前完成其工作。该计划并不关心是否有长时间停顿:

for (;;) {
    last if eof(STDIN);
    print "Got line " . readline(STDIN);
    }

如果我在Perl 6(Rakudo 2017.07)中做同样的事情,程序会马上停止:

$ perl print-stdin.pl
this
Got line this
is
Got line is
a
Got line a
line
Got line line

我真的在一个use v6; loop { last if $*IN.eof; put "Got line " ~ $*IN.get; } 之后可以给我一行输入(可能来自一个缓慢输出长暂停行的程序)但是我一直支持这个简单的问题。我没有找到一种内置的方法来做这件事(这对于这样一个常见任务来说有点令人惊讶)。

1 个答案:

答案 0 :(得分:3)

最近似乎效果更好。
虽然您所写的内容具有竞争条件,因为在调用.eof之后可以关闭输入。这意味着在.get被阻止时可能会发生这种情况,因此会返回Nil。这将导致抛出警告,并打印额外的Got line 

最好只使用.lines

中的Iterator
for $*IN.lines { put "Got line $_" }

或使用.get的返回值来确定输入何时关闭。

loop {
  with $*IN.get {
    put "Got line $_"
  } else {
    last
  }
}

如果您想从输入行获取供应:

$*IN.lines.Supply
react {
  start whenever $*IN.lines.Supply {
    put "Got line $_";
    LAST done; # finish the outer 「react」 block when this closes
  }
  whenever Supply.interval(1) {
    put DateTime.now.hh-mm-ss
  }
}
22:46:33
22:46:34
a
Got line a
22:46:35
22:46:36
b
Got line b
22:46:37
22:46:38
c
Got line c
22:46:39
22:46:40
d
Got line d
22:46:41
22:46:42
^D               # represents Ctrl+D

上面需要start,因此它不会阻止Supply.interval(1)供应正常启动。

如果由于某种原因无法实现上述目的,您可以创建这样的供应:

my \in-supply = supply {

  # 「await start」 needed so this won't block other things on this thread.

  await start loop {
    with $*IN.get { # defined (so still open)

      emit $_

    } else {        # not defined (closed)

      done;         # stop the Supply

      # last        # stop this loop (never reached)

    }
  }
}

react {
  whenever in-supply {
    put "Got line $_";
    LAST done # finish the outer 「react」 block when this closes
  }
  whenever Supply.interval(1) {
    put DateTime.now.hh-mm-ss
  }
}