2015-01-11 5 views
10

が、彼はそうのように、別のstateFnを返す関数型stateFnを定義します。ルーストに似た何かをしようとする試みで再帰関数型<a href="https://www.youtube.com/watch?v=HxaD_trXwRE#t=855">Rob Pike's talk</a>で

type stateFn func() stateFn 

、私はこれを試してみました:

type stateFn = fn() -> stateFn; 

コンパイラは「不正な再帰型です;サイクル内に列挙型または構造体を挿入します(必要な場合)」。

私はこれをRustで行うことができますか?

答えて

15

関数型を公称型(つまり、構造体または列挙型)にラップすることができます。錆のtypeはC.でHaskellではtypetypedef

ので、1つのテースト、単なる別名である一方でtype T Uは、Uと直接交換可能ではありません新しい、特殊タイプTを定義しています。これは、実際に行くのコードがやっていることです書き込み:

struct StateFn(fn() -> Option<StateFn>); 

または

struct StateFn { 
    f: fn() -> Option<StateFn> 
} 

(私はOptionために行くのを追加しなければなりませんでした錆が、それはオプトインを作り、デフォルトでNULL値の許容を取り除きながら、nilにすることができます。)

前記、ルストfnだけである一方で、私は、(いくつかの内部状態を保存することができます)funcが行くで閉鎖されると思われます(全くステートはありません)ので、Rustでもクロージャーを使いたいかもしれません。これは、fn() -> Option<StateFn>Box< Fn() -> Option<StateFn>>に置き換えて、Box::new(move || { /* code here */ })で作成することで可能です。

Fnの代わりにFnMutを使用することもできます。これにより、柔軟性が向上します。FnOnceは一度しか呼び出せないクロージャを表します。これらのそれぞれは、呼び出し元に対する連続的な制限を設けていますが、クロージャそのものに次々と柔軟性を与えています。 (ただし、「オブジェクトの安全性」の懸念がBox<FnOnce>は、現時点では動作しないことを意味し、"Purging proc"は詳細と回避策があります。)

struct StateFn { 
    f: Box<FnMut() -> Option<StateFn>> 
} 

これらのいずれかの状況の解析ループは次のようになります。

let mut state_fn = Some(initial_fn); 
while let Some(mut f) = state_fn { 
    state_fn = (*f.f)() 
} 
+0

Fnは呼び出し元に最も制限をかけます(環境を変更しないでください).FnOnceは環境を消費/移動することさえできます。 FnOutはFnMutに実装され、FnMutはFnに実装されます。私はここでFnOnceが最適だと思う。 –

+1

いいえ、*呼び出し側*は 'Fn'に対して最も制限がありません。 'FnMuth'や' FnOnce'のどちらも呼び出すことができませんが、 'FnOnce'はby-valueで呼び出されなければならず、一度だけ呼び出すことができます(これははるかに制限的です) 。一方、 'Fn'は* callee *(クロージャ自体)に最も制限を設け、' FnOnce'はクロージャのために最も制限の少ないものです(つまり、 'FnOnce'クロージャのボディが最も柔軟性があります)。答えが説明しているように、 'FnOnce'が最高ですが、特性オブジェクトの周りに微妙なところがあります。つまり、それは直接作用しません。 – huon

+0

はい、そうです。私は引数としてFnOnce/FnMut/Fnをとる関数を考えました。 –