Rust 如何将结构的生存期限制为';家长';结构?
我正在使用FFI编写一些针对具有强烈所有权概念(API,如果有关系的话)的C API的代码 API的主要入口点是数据库;我可以从数据库中创建查询对象。它为数据库和查询(以及许多其他对象)提供析构函数 但是,查询的生存期不能超过创建查询的数据库。数据库析构函数将销毁任何未受破坏的查询等,之后查询析构函数将不工作 到目前为止,我已经完成了基本的工作——我可以创建数据库和查询,并对它们进行操作。但是我很难对生命的界限进行编码 我正在尝试这样做:Rust 如何将结构的生存期限制为';家长';结构?,rust,lifetime,Rust,Lifetime,我正在使用FFI编写一些针对具有强烈所有权概念(API,如果有关系的话)的C API的代码 API的主要入口点是数据库;我可以从数据库中创建查询对象。它为数据库和查询(以及许多其他对象)提供析构函数 但是,查询的生存期不能超过创建查询的数据库。数据库析构函数将销毁任何未受破坏的查询等,之后查询析构函数将不工作 到目前为止,我已经完成了基本的工作——我可以创建数据库和查询,并对它们进行操作。但是我很难对生命的界限进行编码 我正在尝试这样做: struct Db<'a>(...) //
struct Db<'a>(...) // newtype wrapping an opaque DB pointer
struct Query<'a>(...) // newtype wrapping an opaque query pointer
我不知道用什么来代替?
s,这样就不允许返回的查询比数据库寿命长
如何对此API的生存期约束建模?如果要将输入参数的生存期绑定到返回值的生存期,则需要在函数上定义生存期参数,并在输入参数和返回值的类型中引用它。您可以为该生存期参数指定任何名称;通常,当参数很少时,我们只将它们命名为
'a
,'b
,'c
,等等
您的Db
类型接受生存期参数,但它不应该:Db不引用现有对象,因此它没有生存期约束
要正确地强制Db
超过查询
,我们必须在借用的指针上写入'a
,而不是刚才删除的Db
上的生存期参数
pub fn create_query<'a>(db: &'a Db, query_string: &str) -> Query<'a>
这是因为,在Rust 1.0之前,生存期参数是双变量的,即编译器可以用更长或更短的生存期替换参数,以满足调用方的要求
在结构中存储借用的指针时,生存期参数被视为协变的:这意味着编译器可以用更短的生存期替换参数,但不能用更长的生存期
我们可以要求编译器通过向结构添加PhantomData
标记,手动将您的生存期参数视为协变参数:
use std::marker::PhantomData;
struct Db(*mut ());
struct Query<'a>(*mut (), PhantomData<&'a ()>);
fn create_query<'a>(db: &'a Db, query_string: &str) -> Query<'a> { // '
Query(0 as *mut (), PhantomData)
}
fn main() {
let query;
{
let db = Db(0 as *mut ());
let q = create_query(&db, ""); // error: `db` does not live long enough
query = q;
}
}
当一个方法有一个
self
参数时,编译器会倾向于将该参数的生存期与结果链接起来,即使还有其他参数具有生存期。但对于自由函数,只有当只有一个参数具有生存期时,才可能进行推断。这里,由于query\u string
参数的类型为&'a str
,因此有两个参数具有生存期,因此编译器无法推断我们要将结果链接到哪个参数。谢谢!在这种设计中,我编写的测试函数的生存期不好,现在被编译器正确地拒绝了。这已经过时了,但是通用模式可以工作。现在&'a T
和&'a mut T
在'a
上总是协变的,因此std::marker::ContravariantLifetime
不再存在。但是必须使用声明的任何类型参数,因此现在需要使用std::marker::PhantomData
。
struct Db(*mut ());
struct Query<'a>(*mut ()); // '
fn create_query<'a>(db: &'a Db, query_string: &str) -> Query<'a> { // '
Query(0 as *mut ())
}
fn main() {
let query;
{
let db = Db(0 as *mut ());
let q = create_query(&db, "");
query = q; // shouldn't compile!
}
}
use std::marker::PhantomData;
struct Db(*mut ());
struct Query<'a>(*mut (), PhantomData<&'a ()>);
fn create_query<'a>(db: &'a Db, query_string: &str) -> Query<'a> { // '
Query(0 as *mut (), PhantomData)
}
fn main() {
let query;
{
let db = Db(0 as *mut ());
let q = create_query(&db, ""); // error: `db` does not live long enough
query = q;
}
}
use std::marker::PhantomData;
struct Db(*mut ());
struct Query<'a>(*mut (), PhantomData<&'a ()>);
impl Db {
//fn create_query<'a>(&'a self, query_string: &str) -> Query<'a>
fn create_query(&self, query_string: &str) -> Query {
Query(0 as *mut (), PhantomData)
}
}
fn main() {
let query;
{
let db = Db(0 as *mut ());
let q = db.create_query(""); // error: `db` does not live long enough
query = q;
}
}