集合に含まれるリストに関する混乱、おそらくコンテキストの問題?


8

Rakudoバージョン2020.01

私は使い捨てのコードをいくつか書いていて、クラスを実装する気にせず、同じようにハッシュを使用しました。リストでいくつかの驚くべき動作を見つけました。

class Q1 {}
class R1 {
    has Str $.some-str is required;
    has @.some-list is required;
}

my $r1 = R1.new(
    some-str => '…',
    some-list => (Q1.new, Q1.new, Q1.new)
);

# hash as poor man's class
my $r2 = {
    some-str => '…',
    some-list => (Q1.new, Q1.new, Q1.new)
};

multi sub frob(R1 $r1) {
    for #`(Array) $r1.some-list -> $elem {
        $elem.raku.say;
    }
}

multi sub frob(Hash $r2) {
    for #`(List) $r2<some-list> -> $elem {
        $elem.raku.say;
    }
}

frob $r1;
# OK.
# Q1.new
# Q1.new
# Q1.new

frob $r2;
# got:
# (Q1.new, Q1.new, Q1.new)

# expected:
# Q1.new
# Q1.new
# Q1.new

frob(Hash …)を呼び出したとき、.flatまたは.listリスト上で期待どおりに機能します(すでにリストである場合でも)。

最小限のテストケースを作成しようとしましたが、これは同じAFAICTで機能します。

for [Q1.new, Q1.new, Q1.new] -> $elem {
    $elem.raku.say;
}

for (Q1.new, Q1.new, Q1.new) -> $elem {
    $elem.raku.say;
}

ListとScalarのドキュメントを何度か読んだことがありますが、それでも自分の観察結果を理解することはできません。クラスではなく、ハッシュでリストを特別扱いする必要があるのはなぜですか?


私が取得No such method 'raku' for invocant of type 'Q1'私はこれを実行しようとすると
ホーコンHægland

2
@HåkonHægland:それはかつて呼ばれていました.perl:おそらくあなたの楽道は十分に最新ではありませんか?
Elizabeth Mattijsen

回答:


10

for 項目化された値をループしません。

スカラーコンテナーに何かを配置すると、アイテム化されます。

sub foo ( $v ) { # itemized
  for $v { .say }
}
sub bar ( \v ) {
  for v { .say }
}

foo (1,2,3);
# (1 2 3)

bar (1,2,3);
# 1
# 2
# 3

ハッシュ内の要素もスカラーコンテナーです。

my %h = 'foo' => 'bar';

say %h<foo>.VAR.^name;
# Scalar

したがって、リストをハッシュに配置すると、項目化されます。

my %h;

my \list = (1,2,3);
%h<list> = list;

say list.VAR.^name;
# List
say %h<list>.VAR.^name;
# Scalar

そのため、値をループしたい場合は、項目を細かくする必要があります。

%h<list>[]
%h<list><>
%h<list>.list
%h<list>.self

@(%h<list>)

given %h<list> -> @list {  }

my @list := %h<list>;

(my @ := %h<list>)  # inline version of previous example

代わりにバインドすることで、このスカラーコンテナーを回避できます。

%h<list> := list;

(これにより、=オペレーターはそのハッシュ要素で作業できなくなります。)


クラスオブジェクトでそれを@notで定義したことに気付いた場合$

class R1 {
    has Str $.some-str is required;
    has @.some-list is required;
}

に変更して$マークを付けるとrw、ハッシュの例のように機能します

class R2 {
    has Str $.some-str is required;
    has List $.some-list is required is rw;
}

my $r2 = R2.new(
    some-str => '…',
    some-list => (1,2,3),
);

for $r2.some-list { .say }
# (1 2 3)

それはなければならない$変数またはそれはスカラーコンテナになりません。
またrw、アクセサが項目別の値ではなく実際のScalarコンテナを返すようにマークする必要があります。


6

これは、とは何の関係もありません[]対を()。これは$%(アイテムを示す)と(Associativeを示す)の違いに関係しています。

sub a(%h) { dd %h }       # a sub taking an Associative
sub b(Hash $h) { dd $h }  # a sub taking an item of type Hash

a { a => 42 };  # Hash % = {:a(42)}
b { a => 42 };  # ${:a(42)}

「b」の場合、受け取るのはアイテムです。それを反復しようとすると、その項目に対して1回の反復が行われます。一方、「a」の場合は、(%シギルを使用して)必要なアソシエーティブなものであることを示しました。

おそらくより明確な例:

my $a = (1,2,3);
for $a { dd $_ }  # List $a = $(1, 2, 3)␤

以来$aアイテムである、あなたは一回の反復を取得します。以下を追加することで、基礎となるものを反復したいことを示すことができます.list

for $a.list { dd $_ }  # 1␤2␤3␤

または、さらにラインノイズを増やしたい場合は、プレフィックスaを付け@ます。

for @$a { dd $_ }  # 1␤2␤3␤

1
しかし、マルチサブフロブでは、ハッシュやアイテムではなく、クラスの属性またはハッシュのメンバーによってアクセスされる配列またはリストに対して繰り返します。タイプを確認し、関連する場所にインラインコメントで注釈を付けました。
daxim

5

厳密には答えではありませんが、観察です。Rakuでは、Perlとは異なり、ハッシュではなくクラスを使用するほうが効果的です。

my %h = a => 42, b => 666;
for ^10000000 { my $a = %h<a> }
say now - INIT now;  # 0.4434793

クラスとオブジェクトの使用:

class A { has $.a; has $.b }
my $h = A.new(a => 42, b => 666);
for ^10000000 { my $a = $h.a }
say now - INIT now;  # 0.368659

クラスをより速く使用できるだけでなく、is requiredトレイトを追加した場合に初期化でタイプミスを防ぐこともできます。

class A { has $.a is required; has $.b is required }
A.new(a => 42, B => 666);
# The attribute '$!b' is required, but you did not provide a value for it.

そしてそれはあなたがそれにアクセスするときにタイプミスをするのを防ぎます:

my $a = A.new(a => 42, b => 666);
$a.bb;
# No such method 'bb' for invocant of type 'A'. Did you mean 'b'?

1
私が書いているドキュメントにリンクするための何かを私にくれてありがとう!しばらく前にクラス+属性>高速化のためのハッシュであると誰かが言ったことを知っていますが、それを見つけることができませんでした。私は現在、CLDRモジュールを作り直して、ハッシュバックアップで属性を使用するようにしています(これにより、驚くほどユーザーフレンドリーですFALLBACK
user0721090601
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.