Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return a &Path from a function?

Tags:

rust

I'm trying to understand how to write proper Rust code, but I think I may be overestimating the power of the compiler's ability to understand the lifetimes of my objects. This is the code as I expected it to work:

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();
}

When I try to compile this, I get an error about a missing lifetime specifier on &Path. I know if this took a reference parameter from the caller, it would take on the same lifetime as that reference has. Here though what I was expecting is that the lifetime would be attached to the variable I am assigning the result to.

I know lifetimes can be added explicitly, but I don't know how to apply them in this case. The compiler suggests trying the 'static lifetime, but that doesn't make sense here as far as I know because the source of this function's return value isn't static.

Now, just to try to see what happened if I tried to compile the rest of the code, I changed the return type from &Path to PathBuf and called as_path() in open(). This caused the compiler to output these errors:

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() returns a Result<SqliteConnection, SqliteError> and the only field inside SqliteConnection is a RefCell, so I don't understand where this error about a byte array is coming from.

So, why aren't things working as I expect and what is the most Rusty way to write this code?

like image 451
Austin Wagner Avatar asked Sep 06 '15 01:09

Austin Wagner


People also ask

How do I return something?

Tell the clerk you want to return the item. Go to the returns department if there is one, or to a cashier. Smile and explain that you want to return an item and why. Remember to be friendly.

How do you return QR codes?

Conducting a return with a QR code is simple. Towards the end of a normal return flow, a shopper will now have the option to select between Print & Shop, or the new Scan & Go tab in a new Choose your return option step. After selecting Scan & Go, the shopper would click on "Click here to find your closest location".


1 Answers

In your first case, you are creating a value and then trying to return a reference to it. But since you aren't storing that value anywhere, it gets destroyed after the function ends. If it was allowed, it'd be a use-after-free bug.

The reason it suggested returning a &'static Path is because the function isn't parameterized over any lifetimes, so the only lifetime you can be sure outlives anything that wants to use the return value would be 'static.

You are correct that you need to return a PathBuf directly instead of an &Path.

I'm not quite sure why you are getting the [u8] sized errors.

You don't need to call "as_path()" at all. SqliteConnection::open takes a value that implements AsRef<Path> (AsRef is sort of like Into), and PathBuf does implement that trait.

like image 136
Havvy Avatar answered Oct 24 '22 21:10

Havvy