2015-09-06 5 views
5

Я пытаюсь понять, как писать правильный код ржавчины, но я думаю, что я могу переоценить способность компилятора понять времена жизни моих объектов. Это код, как я ожидал, что он работает:Как вернуть & & путь из функции?

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, но это не имеет смысла здесь, насколько я знаю, потому что источник возвращаемого значения этой функции не является статическим.

Теперь, просто попытаться посмотреть, что случилось, если бы я попытался собрать остальную часть кода, я изменил тип возвращаемого из &Path в PathBuf и называется as_path() в open(). Это вызвало компилятор для вывода этих ошибок:

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() возвращает Result<SqliteConnection, SqliteError> и единственное поле внутри SqliteConnection является RefCell, так что я не понимаю, где эта ошибка о массиве байт откуда.

Итак, почему не все работает так, как я ожидаю, и какой самый ржавый способ написать этот код?

ответ

7

В вашем первом случае вы создаете значение, а затем пытаетесь вернуть ссылку на него. Но поскольку вы не храните это значение нигде, он уничтожается после завершения функции. Если бы это было разрешено, это было бы ошибкой использования после сбоев.

Причина, по которой он предложил вернуть &'static Path, заключается в том, что функция не параметризируется в течение любых жизней, поэтому единственное время жизни, которое вы можете быть уверены, переживает все, что хочет использовать возвращаемое значение, будет 'static.

Вы правы, что вам необходимо вернуть PathBuf вместо &Path.

Я не совсем уверен, почему вы получаете ошибки размера [u8].

Вам вообще не нужно называть «as_path()». SqliteConnection::open принимает значение, которое реализует AsRef<Path> (AsRef является своего рода Into), и PathBuf действительно реализует эту черту.

+0

Я понимаю, что в первом случае я возвращаю ссылку на что-то, созданное внутри функции, но если я сделаю getPath() функцией-членом SomeDatabase, компилятор достаточно умен, чтобы удерживать & Path до экземпляра SomeDatabase выходит за рамки. Я спрашиваю, есть ли способ сообщить компилятору, что время жизни ссылки принадлежит функции, вызывающей getPath() (в случае, когда getPath() является связанной функцией). Код жизненного цикла должен быть до тех пор, пока переменная, содержащая ссылку, не выходит из области действия в open(). –

+0

Также нужно добавить, что если я оставил as_path(), я получаю ошибку с несогласованными типами: «expected» & _ ', found' std :: path :: PathBuf '(expected & -ptr, found struct' std :: path :: PathBuf ') –

+1

@AustinWagner Переменная 'path' определяется в теле метода' getPath() ', его время жизни заканчивается в конце области действия этого тела функции, если вы не вернете его. чтобы избежать этого правила. В вашем случае нет альтернативы возврату функции 'PathBuf' для' getPath() '. – Levans

Смежные вопросы