4

への各呼び出しの前に、 Perl にFETCHSIZEtie された配列を強制的に呼び出す方法はありますFETCHか? 結合された配列は最大サイズを認識していますが、以前のFETCH呼び出しの結果によっては、このサイズから縮小する可能性があります。以下は、リストを遅延評価で偶数要素のみにフィルター処理する不自然な例です。

use warnings;
use strict;

package VarSize;

sub TIEARRAY { bless $_[1] => $_[0] }
sub FETCH {
    my ($self, $index) = @_;
    splice @$self, $index, 1 while $$self[$index] % 2;
    $$self[$index]
}
sub FETCHSIZE {scalar @{$_[0]}}

my @source = 1 .. 10;

tie my @output => 'VarSize', [@source];

print "@output\n";  # array changes size as it is read, perl only checks size
                    # at the start, so it runs off the end with warnings
print "@output\n";  # knows correct size from start, no warnings

簡潔にするために、一連のエラー チェック コードを省略しました (0 以外のインデックスから始まるアクセスの処理方法など)。

編集: 上記の 2 つの print ステートメントではなく、次の 2 行のいずれかを使用すると、最初の行は正常に動作し、2 番目の行は警告をスローします。

print "$_ " for @output;   # for loop "iterator context" is fine,
                           # checks FETCHSIZE before each FETCH, ends properly

print join " " => @output; # however a list context expansion 
                           # calls FETCHSIZE at the start, and runs off the end

アップデート:

可変サイズの結合された配列を実装する実際のモジュールはList::Genと呼ばれ、CPAN 上にあります。関数は のfilterようgrepに動作しますが、List::Genの遅延ジェネレーターで動作します。の実装をfilter改善できるアイデアはありますか?

(test関数は似ていますがundef、失敗したスロットに戻り、配列のサイズを一定に保ちますが、もちろん使用方法のセマンティクスは とは異なりますgrep)

4

2 に答える 2

1
sub FETCH {
    my ($self, $index) = @_;
    my $size = $self->FETCHSIZE;
    ...
}

タダ!

あなたが見逃しているのは、それらが単なるメソッドであると思われます。メソッドはタイ マジックによって呼び出されますが、自分で呼び出すことができるメソッドにすぎません。

結合された配列の内容を一覧表示すると、基本的に次のようになります。

my @array;
my $tied_obj = tied @array;
for my $idx (0..$tied_obj->FETCHSIZE-1) {
    push @array, $tied_obj->FETCH($idx);
}

return @array;

したがって、反復回数を制御する機会はありません。またはまたはFETCHから呼び出されているかどうかも確実にわかりません。これはひどい。ネクタイはちょっとひどいです、そして彼らは本当に遅いです。通常のメソッド呼び出しの約 3 倍、通常の配列の約 10 倍遅くなります。@array$array[$idx]@array[@idxs]

あなたの例は、配列に関する期待をすでに破っています(10個の要素が入り、5個の要素が出てきます)。ユーザーが を要求するとどうなり$array[3]ますか? 彼らは得undefますか?代替手段には、オブジェクト API を使用することも含まれます。あなたのものが配列のように振る舞わない場合は、混乱を招くだけです。または、配列の逆参照をオーバーロードしたオブジェクトを使用できます。

つまり、あなたがやっていることはできますが、うまく機能させるのは難しいです. あなたは本当に何を達成しようとしていますか?

于 2009-12-21T20:55:21.283 に答える
0

FETCH/FETCHSIZEperl がメソッドを呼び出す順序は変更できないと思います。それはperlの内部部分です。明示的に警告を削除しない理由:

sub FETCH {
    my ($self, $index) = @_;
    splice @$self, $index, 1 while ($$self[$index] || 0) % 2;
    exists $$self[$index] ? $$self[$index] : '' ## replace '' with default value
}
于 2009-12-21T22:37:30.250 に答える