0

私は Rust の学習を始めたばかりで、主に JavaScript のバックグラウンドを持っているため、借用システム全体とメモリ管理に関しては少し困惑しています。

次のコードがあります。

fn load(db: &MyPool, id: i32) -> &Account{
    let accounts: Vec<Account> = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
    .and_then(|mut stmt| {
        stmt.execute(&[&id]).map(|result| {
            result.map(|x| x.unwrap()).map(|row| {
                Account{
                    id: from_value(&row[0]), 
                    balance: from_value(&row[1]), 
                    name: from_value(&row[2])
                }
            }).collect()
        })
    }).unwrap();

    &accounts[0]

}

そして、コンパイラがスローするすべてのエラーを修正することができました /main.rs:42:4: 42:12 error: 'accounts' does not live long enough

これは、MySQL クエリから 1 つの結果を取得するための最良の方法ですか、それとも完全に間違っていますか?

4

1 に答える 1

2

アカウントへの参照を返したくはありませんが、データベースから取得した後に所有権を呼び出し元に渡したいとします。

したがって、署名を次のように変更します。

fn load(db: &MyPool, id: i32) -> Account

ここでのアイデアは、オブジェクトを参照ではなく値で返すことです。

accounts[0]

ただし、これを行うと失敗し、error: cannot move out of indexed content. より良いアプローチは、ベクトルでの収集を完全に避けIterator::next(&self)、最初の要素を取得するために使用することです。これは次のようになります。

fn load(db: &MyPool, id: i32) -> Account{
    let account: Account = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
    .and_then(|mut stmt| {
        stmt.execute(&[&id]).map(|result| {
            result.map(|x| x.unwrap()).map(|row| {
                Account{
                    id: from_value(&row[0]), 
                    balance: from_value(&row[1]), 
                    name: from_value(&row[2])
                }
            }).next().unwrap() // <- next() takes the first elt of the iterator
        })
    }).unwrap();

    account // <- return by value, pass ownership to caller
}

(開発環境を再現できなかったため、未テストです。)

無関係ですが、これらの複数のunwrap()呼び出しは関数を非常に脆弱にすることに注意してください。失敗すると、プログラム全体がパニックでクラッシュします。Option<Account>幸いなことに、この悪臭に対する答えは簡単ですAccount。次に、 へのすべての呼び出しを削除し、呼び出し全体に伝播unwrap()させます (「見つかったら戻り、見つかったら戻る」と表示されるため、 の使用は適切です)。Option<Account>map()NoneNoneSome(f(a))Some(a)

于 2015-07-11T11:17:19.500 に答える