2015-09-06 13 views
5

私は適切な錆のコードを書く方法を理解しようとしていますが、私は私のオブジェクトの寿命を理解するコンパイラの能力のパワーを過大評価していると思います。私はそれが動作するように期待通りこれはコードです:関数から&Pathを返すにはどうすればよいですか?

use std::path::Path; 
use std::env; 
use rusqlite::SqliteConnection; 

struct SomeDatabase { 
    conn: SqliteConnection, 
} 

impl SomeDatabase { 
    fn getPath() -> &Path { 
     let path = env::home_dir().unwrap(); 
     path.push("foo.sqlite3"); 
     path.as_path() 
    } 

    fn open() -> SomeDatabase { 
     let path = SomeDatabase::getPath() 
     SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
    } 
} 

fn main() { 
    let db = SomeDatabase::open(); 
} 

私はこれをコンパイルしようとすると、私は&Pathに欠け寿命指定子に関するエラーが発生します。私はこれが呼び出し元からの参照パラメータを取るかどうかを知っている、それは参照が持っているのと同じ生涯かかるだろう。ここで私が期待していたのは、生涯が変数に結びついて、結果を割り当てることです。

私は寿命を明示的に追加することができますが、私はこの場合にどのように適用するのか分かりません。コンパイラは寿命が'staticであることを示唆していますが、この関数の戻り値のソースが静的ではないため、ここではわかりません。ちょうど私が残りのコードをコンパイルしようとした場合には何が起こったかを確認するためにしようとする今、

は、私が PathBuf&Pathから戻り値の型を変更し、 open()as_path()と呼ばれます。これは、出力するコンパイラこれらのエラー原因:

src\main.rs:22:30: 22:52 error: the trait `core::marker::Sized` is not implemented for the type `[u8]` [E0277] 
src\main.rs:22   SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
              ^~~~~~~~~~~~~~~~~~~~~~ 
src\main.rs:22:30: 22:52 note: `[u8]` does not have a constant size known at compile-time 
src\main.rs:22   SomeDatabase { conn: SqliteConnection::open(path).unwrap() } 
              ^~~~~~~~~~~~~~~~~~~~~~ 

SqliteConnection::open()SqliteConnection内部のみフィールドがRefCellあるResult<SqliteConnection, SqliteError>を返すとし、そのバイト配列については、このエラーはどこから来ている私は理解していません。

私は期待どおりに動作していないのですが、このコードを書いた最もラスティックな方法は何ですか?

答えて

7

最初のケースでは、値を作成してから、その値を参照しようとしています。しかし、あなたはその値をどこにも格納していないので、関数が終了した後は破棄されます。許可されていれば、それはuse-after-freeバグでしょう。

&'static Pathを返すように提案された理由は、関数がどのような生涯にわたってパラメータ化されていないためです。戻り値を使用するものよりも寿命が長いことを確認できる唯一の寿命は'staticです。

&Pathの代わりにPathBufを直接返す必要があることは間違いありません。

なぜ[u8]サイズのエラーが発生するのかよく分かりません。

"as_path()"を呼び出す必要はありません。 SqliteConnection::openAsRef<Path>AsRefIntoのようなものです)を実装する値をとり、PathBufはその特性を実装します。

+0

最初のケースでは、関数内で作成されたものへの参照を返していますが、SomeDatabaseのメンバー関数getPath()を作成すると、コンパイラはSomeDatabaseのインスタンスまで&Pathを保持できるほどスマートです範囲外になる。私は参照の寿命がgetPath()(getPath()が関連する関数である場合)を呼び出している関数に属していることをコンパイラに伝える方法があるかどうかを尋ねています。ライフタイムコードは、参照を保持する変数がopen()の有効範囲外になるまで保持する必要があります。 –

+0

また、as_path()を終了すると、 "expected '&_'、 'std :: path :: PathBuf'(期待された&-ptr、構造体の 'std :: path'が見つかりました。 :: PathBuf ') –

+1

@AustinWagner変数 'path'は' getPath() 'メソッドの本体に定義されています。戻り値を返さない限り、この関数本体のスコープの終わりで終わります。あなたのケースでは、 'PathBuf'を' getPath() '関数に返す代わりの手段はありません。 – Levans

関連する問題