2012-01-20 16 views
2

私はPerlで状態マシンを作ろうとしています。これを行うために、私は配列がstatenamesによって索引付けされています。私はこの配列にサブを置くことができます。このように:Perlが配列の内部にあるサブルーチンを呼び出す

use constant { 
    stInit   => 0, 
    stHeader  => 1, 
    stSalesHeader => 2, 
    stCatagory  => 3, 
    stData   => 4, 
    stTotal   => 5, 
    stError   => 6, 
}; 

my $state = stInit; 
my @actions; 

$actions[stInit] = [sub{logState("Initial state entered",2) }]; 
$actions[stHeader] = [sub{logState("Header state entered",2) }]; 
$actions[stSalesHeader] = [sub{logState("Sales header state entered",2) }]; 
$actions[stCatagory] = [sub{logState("Category state entered",2) }]; 
$actions[stData] = [sub{logState("Data state entered",2) }]; 
$actions[stTotal] = [sub{logState("Total state entered",2) }]; 

しかし、その後、私はどのようにサブルーチンを呼び出すには考えています。私はこれを試しました

$actions[$state] 

しかし、それは動作していないようです。これは可能ですか、それとも完全にオフですか?

&{$actions[$state]}(); 

しかし、あなたのコードに基づいて、@actionsは、サブルーチンの参照を含めることはできませんが、サブルーチンの宣言に、配列の参照:参照からサブルーチンを呼び出すために

答えて

9

あなたは本当にのための多くの単純なミスを見つけなる、あなたのコードの先頭に

use strict; 
use warnings; 

を追加する必要があります君は。この場合、あなたのコードは結構です、とあなたは

$actions[$state][0](); 

を使用してサブルーチンを呼び出すことができますなど

しかし、角括弧内のサブルーチンを置く必要はありません、ただ一要素匿名を作成します配列とは、したがって、インデックスの追加レベル(上記のコード行で[0]を追加します。あなたは、あなたが

でサブルーチンを呼び出すことができるだろう、この代わりに

$actions[stInit] = sub { logState("Initial state entered", 2) }; 

のようなコードを書いた場合

$actions[$state](); 
+1

'()'を使うと、間違って '@ _ 'を継承することを避け、'& 'を使って誤って継承するのを避けることができます。悪い習慣IMOです。 –

+4

確かに。 '&'の非難解な唯一の使用法は '\&mysub'を使ってサブルーチンへの参照にアクセスすることです。それは何年もの間このようになってきました。 – Borodin

+0

@Borodin、 '$ ref - >()'と同様に、 '&$ ref()'も '@ _'を継承しません。 – ikegami

1

まず、通常どおり、その後@actionsを構築する潜水艦を宣言:

$actions[0] = \&stInit; 
$actions[1] = \&stHeader; 
...and so on 
+0

サブルーチンを呼び出すときにアンパサンドを使用すると、古くなって非常に悪いことになります。ちょうど '$ actions [$ state]()'はうまくいきます。 – Borodin

1

あなたが行う必要があります。

&{$actions[$state][0]} 

しかし、あなたは、配列を使用する理由私はわかりません。.. 。機能が1つしかない場合は、

$actions[stData] = sub{ ... } 
... 
&{$actions[$state]} 

となります。あなたは本当に多くの機能を実行し、配列を使用したい場合は、行うことができます。

map { &{$_} } @{$actions[$state]}; 
+1

もう一度、2つの答えについては、非常に古いバージョンのPerlでは '$ actions [$ state]()'を使用してください。また、 'map'を副作用として使用し、結果を破棄するという罪を犯しています。 – Borodin

2

少し異なる点として、FSA::Rulesを使用して状態マシンを書き込んでみましたか?これはかなり強力で、オプションのGraphViz出力を持ち、ステートマシンを簡単に書くことができます。

+0

答えをありがとう、これは私が必要とするものです。 –

1

あなたはアクションが変数に格納されている場合は、その後

$actions[stInit](); 

とアクションを呼び出すことができます

$actions[stInit] = sub{logState("Initial state entered",2) }; 

角括弧を除去することにより、余分な無名配列の作成をドロップし、例えば

my $action = $actions[$actionID]; 

あなたはあなただけの配列

my %actions = (
    stInit  => sub { logState("Initial state entered",2) }, 
    stHeader  => sub { logState("Header state entered",2) }, 
    stSalesHeader => sub { logState("Sales header state entered",2) }, 
    stCatagory => sub { logState("Category state entered",2) }, 
    stData  => sub { logState("Data state entered",2) }, 
); 

の代わりにハッシュを使用することができ、それは実際に再び

$action->(); 

その後の呼び出しを行う作るために少しより多くの構文が必要になります上部に定数を設定する必要がなくなります。

$actions{$state}(); 
関連する問題