我想要了解如何编写正确的Rust代码,但我觉得我可能高估了编译器理解我的对象生命周期的能力。这是我期望它可以工作的代码:
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
并在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()
返回一个 Result<SqliteConnection, SqliteError>
,而 SqliteConnection
内部唯一的字段是一个 RefCell
。因此,我不明白这个关于字节数组的错误从哪里来。
那么,为什么事情没有按照我的预期工作,最Rusty的编写代码方式是什么?
path
在getPath()
方法的函数体中定义,其生命周期在该函数体的作用域结束时结束,除非您返回它。无法避免这个规则。在您的情况下,没有其他选择,必须返回getPath()
函数的PathBuf
。 - LevansSqliteConnection::open
接受一个实现了AsRef
的类型的引用作为参数 —— 请注意,它实际上接受的是 实现了AsRef
的类型的引用。我认为这可能是出现大小错误的原因。这似乎是库方面一个奇怪的决定... - Shepmaster