我可以在Perl 5中创建指向字符串的文件句柄,那么在Perl 6中该怎么做?

14
在Perl 5中,我可以创建一个到字符串的文件句柄,并且可以像处理文件一样从字符串中读取或写入数据。这对于处理测试或模板非常有用。
例如:
use v5.10; use strict; use warnings;

my $text = "A\nB\nC\n";

open(my $fh, '<', \$text);

while(my $line = readline($fh)){
    print $line;
}

我怎样才能在Perl 6中实现这一点?下面的并不适用于Perl 6(至少对于我运行在64位CentOS 6.5上的MoarVM 2015.01版本Rakudo Star 2015年1月版的实例来说是不行的):

# Warning: This code does not work
use v6;

my $text = "A\nB\nC\n";

my $fh = $text;

while (my $line = $fh.get ) {
    $line.say;
}
# Warning: Example of nonfunctional code

我收到了以下错误信息:

No such method 'get' for invocant of type 'Str'
   in block <unit> at string_fh.p6:8

Perl5的open(my $fh, '<', \$text)和Perl6的my $fh = $text;不同并不奇怪。那么问题是:如何在Perl 6中像Perl 5中的open(my $fh, '<', \$str)一样从字符串创建虚拟文件句柄?或者这是尚未实现的功能?

更新(在Perl 5中向文件句柄写入)

同样,在Perl 5中,您可以向字符串文件句柄写入:

use v5.10; use strict; use warnings;

 my $text = "";
 open(my $fh, '>', \$text);

 print $fh "A";
 print $fh "B";
 print $fh "C";

 print "My string is '$text'\n";

输出:

 My string is 'ABC'

我还没有在Perl 6中看到任何类似的东西。


1
顺便提一下,代码 while (my $line ...){...} 并没有以你所想象的方式局部限定 $line 的词法作用域。$line 最终的词法作用域是环绕该脚本主要代码体的上下文,并不是仅限于以下大括号内。相反,使用 my 声明的词法变量声明作用域只限于封闭的大括号内。相比之下,参数是限定于以下大括号内的,因为这些是对参数进行操作的代码块。在第一个(也是唯一的)答案中的 -> $line 代码中的 $line 是一个参数。 - raiph
在P5中,$line是一个未声明的变量,在while语句之外(use strict; use warnings;将会揭示这一点),而在P6中它将被识别。 - raiph
@raiph 哦,好的。现在我明白你的第一条评论完全是指Perl 6。我刚试了一个while (my $line = ...循环,在Perl 6中,你是对的,$line在循环外有作用域。但是,它在循环外没有值。循环后,$line.say打印(Any),这意味着它在作用域内,但基本上是未定义的。 - Christopher Bottoms
如果 $line.say 打印出 (Any),那么这就是 $linewhile 循环语句的条件表达式 my $line = ... 中或者在其后续的 while 循环语句块中被赋予的最后一个 "值"。注意,在条件表达式周围加上括号是不必要的。 - raiph
1个回答

11

阅读

逐行阅读的惯用方式是使用 .lines 方法,该方法适用于 StrIO::Handle

它返回一个惰性列表,你可以将其传递给 for,如下所示:

my $text = "A\nB\nC\n";

for $text.lines -> $line {
     # do something with $line
}

写作

my $scalar;
my $fh = IO::Handle.new but
         role {
             method print (*@stuff) { $scalar ~= @stuff };
             method print-nl        { $scalar ~= "\n" }
         };

$fh.say("OH HAI");
$fh.say("bai bai");

say $scalar
# OH HAI
# bai bai

(来源:#perl6,感谢Carl Mäsak。)

更高级的情况

如果您需要一种更复杂的机制来模拟文件句柄,可以在生态系统中使用IO::Capture::SimpleIO::String

例如:

use IO::Capture::Simple;
my $result;
capture_stdout_on($result);
say "Howdy there!";
say "Hai!";
capture_stdout_off();
say "Captured string:\n" ~$result;

我喜欢使用显式的 -> $foo 位来增加教育价值,但实际上 for ... 语句通常更为简洁,例如 for $text.lines { .foo },其中 .foo 方法被调用于 "it"。("It" 是变量 $_,当使用像 for 这样的主题化语法时,它会自动分配。) - raiph
1
@raiph 这是一个偏好问题。我过去经常在 Perl 5 中使用 $_,但现在更喜欢更明确的变量。这可能会稍微冗长一些,但我更注重可维护性而非简洁性。我很高兴 Perl 6 也是 TIMTOWTDI。 - Christopher Bottoms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接