2017-01-15 4 views
5

私のプログラムはrusqliteを使用して、別のデータソースからデータベースを構築します。データベースは、同じように複数のテーブルを作成しますので、私は私がそうするように、再利用可能な機能を作るだろうと思って:コンパイル済みSQL文の問題を借用

fn download_generic<Inserter>(table_name: &str, 
           connection: &mut rusqlite::Connection, 
           inserter: &mut Inserter) 
           -> Result<(), String> 
    where Inserter: FnMut(&str, &json::JsonValue) ->() 
{} 

inserterは、以前に準備されたステートメントから正しい値を結合し、挿入を行う機能であります。

私はこのようにそれを呼び出す:それはすでにinsert_stmtで借りされていますので、私はdownload_generic&mut connectionを渡すことはできませんしかし

let mut insert_stmt = connection 
    .prepare("insert or replace into categories values(?,?);") 
    .unwrap(); 

download_generic("categories", 
       &mut connection, 
       &mut |uuid, jsonproperties| { 
        insert_stmt.execute(&[&uuid, &jsonproperties["name"].as_str().unwrap_or("")]); 
       }); 

RefCellに入れても意味がありません。なぜなら、この作業を行うためにランタイムオーバーヘッドは必要ないはずですからです。

download_genericに渡すラムダによって生成されたinsert_stmtを作成しようとする可能性がありますが、生涯のマーカーをどこにでも追加する必要があり、不自然なように見えます。

+0

'RefCell'に入れても動作しません。' RefCell'はコンパイル時ではなく実行時にチェックしますが、同じ根底にあるチェックは=> **エイリアスXOR Mutability **を実行します。明らかな問題は、同じ接続を(不変的に)借りることはできませんか? 1つの必要な借用が変更可能な場合、あなたは運がありません。 –

+0

'download_generic'がそれを保持するように、insert_stmtを何とかラムダに移動することはできませんか? – njaard

+0

代わりに 'prepare'の代わりに' prepare_cached'を使用して、クロージャ内で準備されたステートメントを取得できますか?競合する借用を避けるために、クロージャに 'connection'を明示的に渡す必要があります。 –

答えて

2

設計上、Rustは、同じオブジェクトに対して同時に不変の借用と可変の借りを同時に行うことを防ぎます。これは、ポインタとデータ競合が発生しないようにするためです。

rusqliteのAPIでは、Connectionのいくつかのメソッドでは、変更可能なselfが必要です。一部のメソッドでは、変更不可能なselfしか必要ありません。しかし、不変のオブジェクトしか返さないメソッドの中には、借用しているオブジェクトをアクティブに戻すものがあります。 prepareがこれの例です。したがって、これらのオブジェクトの1つが有効範囲内にある限り、RustはConnectionで変更可能な借用を許可しません。

おそらく、いくつかのメソッドが可変参照によってselfを取る理由があります。変更可能な参照を必要とすると、呼び出し先がそのオブジェクトへの排他的アクセス権を持つことが保証されます。あなたが使用する必要のある方法に当てはまらないと思われる場合や、これを解決する別の方法があると思われる場合は、ライブラリの保守担当者に問題を報告する必要があります。

具体的には、prepareについては、代わりにクロージャー内からprepare_cachedを呼び出して競合する借用を回避できます。これを行うには、download_genericconnectionをパラメータとしてクロージャに渡す必要があります。そうしないと、connectionに2つの可変借用があり、これは許可されません。

+0

'Connection :: prepare'は、変更不可能な'&self'を受け入れます。したがって、準備された 'Statement'を' Connection'自体と共に渡すことができます。その結果、この問題は簡単に解ける。 – njaard

関連する問題