Given the following code, it seems that I cannot iterate over a Buf if it had been assigned to a variable, unless I cast it to a list, even though it's not a lazy sequence. What gives?
my $file = open $path, bin => True;
$_.chr.say for $file.read: 8; # works well
my $test = $file.read: 8;
$_.chr.say for $test; # fails with "No such method 'chr' for invocant of type 'Buf[uint8]'"
$_.chr.say for $test.list; # works well
$test.is-lazy.say; # False
Individual elements can be pulled out of a list using a subscript. The first element of a list is at index number zero: Variables in Raku whose names bear the @ sigil are expected to contain some sort of list-like object. Of course, other variables may also contain these objects, but @ -sigiled variables always do, and are expected to act the part.
This is actually one of the trickiest parts of Raku list handling to get a firm understanding of. First, be aware that because itemization in Arrays is assumed, it essentially means that $ (…) s are being put around everything that you assign to an array, if you do not put them there yourself.
These are called sequences, which are of type Seq. As it so happens, loops return Seq s. So, it is fine to have infinite lists in Raku, just so long as you never ask them for all their elements.
Variables in Raku whose names bear the @ sigil are expected to contain some sort of list-like object. Of course, other variables may also contain these objects, but @ -sigiled variables always do, and are expected to act the part. By default, when you assign a List to an @ -sigiled variable, you create an Array.
The reason it fails, is that:
my $test = $file.read: 8;
puts the Buf
that is returned by $file.read
into a Scalar
variable, aka inside a container. And containerized is interpreted by for
as itemized, to be considered a single item. So with:
.chr.say for $test;
you're calling the .chr
method on the whole Buf
, rather than on the individual elements.
There are a number of solutions to this:
my $test := $file.read: 8;
This makes sure there is no container by binding the Buf
.
my @test := $file.read: 8;
Same as 1 basically, make the @test
be an alias for the Buf
. Note that this should also use binding, otherwise you'll get the same effect as you saw.
.chr.say for @$test;
By prefixing the @
you're telling to iterate over it. This is basically syntactic sugar for the $test.list
workaround you already found.
Re the $test.is-lazy.say
, that is False
for just about anything, e.g. 42.is-lazy.say; # False
, so that doesn't tell you very much :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With