Rust 如何将结构的生存期限制为';家长';结构?

Rust 如何将结构的生存期限制为';家长';结构?,rust,lifetime,Rust,Lifetime,我正在使用FFI编写一些针对具有强烈所有权概念(API,如果有关系的话)的C API的代码 API的主要入口点是数据库;我可以从数据库中创建查询对象。它为数据库和查询(以及许多其他对象)提供析构函数 但是,查询的生存期不能超过创建查询的数据库。数据库析构函数将销毁任何未受破坏的查询等,之后查询析构函数将不工作 到目前为止,我已经完成了基本的工作——我可以创建数据库和查询,并对它们进行操作。但是我很难对生命的界限进行编码 我正在尝试这样做: struct Db<'a>(...) //

我正在使用FFI编写一些针对具有强烈所有权概念(API,如果有关系的话)的C API的代码

API的主要入口点是数据库;我可以从数据库中创建查询对象。它为数据库和查询(以及许多其他对象)提供析构函数

但是,查询的生存期不能超过创建查询的数据库。数据库析构函数将销毁任何未受破坏的查询等,之后查询析构函数将不工作

到目前为止,我已经完成了基本的工作——我可以创建数据库和查询,并对它们进行操作。但是我很难对生命的界限进行编码

我正在尝试这样做:

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