首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与GAT相关的生存期冲突与互斥临时生存期

与GAT相关的生存期冲突与互斥临时生存期
EN

Stack Overflow用户
提问于 2022-11-12 23:09:12
回答 1查看 56关注 0票数 1

我正在尝试使用GATs将API增强到内存中的数据存储区。数据是以值的形式组织的,其中每个值都包含一个查找键。您可以将其看作是数据库表中的一行,其中整个行都是“值”,但也包含一个或多个主键列。

这个想法是用一个特征来描述这一点,这样你就可以通过提供密钥来寻找一个特定的价值。键必须能够引用值,这样如果值的键-部分是String,您可以只使用&str来查找它。这是GATs输入图片的地方:

代码语言:javascript
复制
pub trait Value {
    type Key<'a>: PartialEq where Self: 'a;

    fn as_key<'a>(&'a self) -> Self::Key<'a>;
}

Key<'a> GAT提供了一个生命周期,as_key()可以用来返回引用内部数据的值。请注意,as_key()不能仅仅返回对键的引用,因为返回的键可以是在Self中不逐字存在的东西,例如复合键。例如,这些都是可能的:

代码语言:javascript
复制
struct Data {
    s: String,
    n: u64,
    // ... more fields ...
}

// example 1: expose key as self.s as a &str key
impl Value for Data {
    type Key<'a> = &'a str;
    fn as_key(&self) -> &str { &self.s }
}

// example 2: expose key as a pair of (self.s.as_str(), self.n)
impl Value for Data {
    type Key<'a> = (&'a str, u64);
    fn as_key(&self) -> (&str, u64) { (&self.s, self.n) }
}

使用此特性的泛型代码示例如下所示:

代码语言:javascript
复制
pub struct Table<T> {
    data: Vec<T>,
}

impl<T: Value> Table<T> {
    fn find<'a: 'k, 'k>(&'a self, k: T::Key<'k>) -> Option<usize> {
        self.data.iter().position(|v| v.as_key() == k)
    }
}

这是很好的工作,你可以玩它在操场上。(一个更现实的例子将需要OrdHashValue::Key构建一个更复杂的存储,但这足以说明这个想法。)

现在,让我们做一个简单的更改,并将表数据存储在Mutex中。代码看起来几乎相同,而且由于它只返回位置,互斥操作应该保持在实现的内部:

代码语言:javascript
复制
struct Table<T> {
    data: Mutex<Vec<T>>,
}

impl<T: Value> Table<T> {
    pub fn find<'a: 'k, 'k>(&'a self, k: T::Key<'k>) -> Option<usize> {
        let data = self.data.lock().unwrap();
        data.iter().position(|v| v.as_key() == k)
    }
}

然而,上面的代码并没有编译--它抱怨“数据寿命不够长”:

代码语言:javascript
复制
error[E0597]: `data` does not live long enough
  --> src/main.rs:18:9
   |
16 |     pub fn find<'a: 'k, 'k>(&'a self, k: T::Key<'k>) -> Option<usize> {
   |                         -- lifetime `'k` defined here
17 |         let data = self.data.lock().unwrap();
18 |         data.iter().position(|v| v.as_key() == k)
   |         ^^^^^^^^^^^              ---------- argument requires that `data` is borrowed for `'k`
   |         |
   |         borrowed value does not live long enough
19 |     }
   |     - `data` dropped here while still borrowed

游乐场

我不太明白这个错误--为什么data需要在我们所比较的键的生命周期中生存呢?我试过:

  • 改变寿命,使'k'a的寿命完全解耦
  • 提取对一个简单函数的比较,该函数接收&'a T&T::Key<'b>,并在比较它们之后返回一个bool (它自己编译)
  • 用显式Iterator::position()循环替换for

但是没有任何帮助,错误总是以某种形式存在。请注意,将v.as_key()k放在同一个闭包(例如像这样)中是完全合法的,只有当您试图比较它们时,才会出现错误。

我对这个问题的直观理解是,与Value::Key<'a>关联的Value::Key<'a>绑定只适用于另一个Key<'a>

是否有可能对生命周期或as_key()接口进行重新工作来解决这个问题?这是这里描述的问题的变体吗?

编辑:按照kmdreko的建议,放松绑定到HRTB for<'b> PartialEq<Self::Key<'b>>PartialEq,修复上面的示例,但是使用泛型中断。例如,Value的这个实现无法编译:

代码语言:javascript
复制
struct NoKey<T>(T);

impl<T> Value for NoKey<T> {
    type Key<'a> = () where T: 'a;
    fn as_key(&self) -> () {
        ()
    }
}

有错误:

代码语言:javascript
复制
error[E0311]: the parameter type `T` may not live long enough
  --> src/lib.rs:38:20
   |
38 |     type Key<'a> = () where T: 'a;
   |                    ^^ ...so that the type `NoKey<T>` will meet its required lifetime bounds

游乐场

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-13 00:13:37

我对这个问题的直观理解是,与Value::Key<'a>关联的Value::Key<'a>绑定只适用于另一个Key<'a>

这是正确的。您可以通过使用一个级别更高的特征来放松这个约束,它要求Key<'a>可以与所有Key<'b>进行比较。

代码语言:javascript
复制
pub trait Value {
    type Key<'a>: for<'b> PartialEq<Self::Key<'b>> // <-----
    where
        Self: 'a;

    fn as_key<'a>(&'a self) -> Self::Key<'a>;
}

我不认为有任何其他方法,因为大多数类型在关联寿命方面都是协变的,但是使用T::Key<'k>,我认为您不能限制'k可以缩短。

在编辑的问题中指出的泛型问题可以通过要求泛型为'static (游乐场)来解决。请注意,'static绑定仅适用于整个值,键仍可能引用值的部分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74417255

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档