GAT相关生命周期与Mutex临时生命周期冲突问题排查
使用GAT优化内存存储API时的Mutex生命周期问题
我正在尝试用**GAT(泛型关联类型)**优化内存数据存储的API。数据以值的形式组织,每个值包含查找键,类似数据库表中的行——整行是“值”,且自带主键列。
我通过trait描述这种结构,实现通过键查找特定值的功能。键需要能引用值内部的数据,比如值的键是String时,只用&str就能查找,这正是GAT的适用场景:
pub trait Value { type Key<'a>: PartialEq where Self: 'a; fn as_key<'a>(&'a self) -> Self::Key<'a>; }
Key<'a>提供生命周期约束,让as_key()可以返回引用内部数据的键。as_key()不能只返回键的引用,因为返回的键可能是复合键这类非Self内部的原始形式,示例如下:
struct Data { s: String, n: u64, // ... 更多字段 ... } // 示例1:将self.s作为&str类型的键暴露 impl Value for Data { type Key<'a> = &'a str; fn as_key(&self) -> &str { &self.s } } // 示例2:将(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) } }
使用该trait的泛型代码示例如下,这段代码可以正常运行:
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) } }
现在我把表数据放到Mutex中存储,代码几乎一致,且只返回位置,Mutex操作本应在内部完成:
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) } }
但这段代码无法编译,报错信息如下:
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
我尝试过调整生命周期解耦、提取比较函数、替换循环方式等方法,都没能解决问题——只有在比较v.as_key()和k时才会触发这个错误。
我认为问题出在Value::Key<'a>的PartialEq约束只适合同生命周期的Key<'a>。有没有办法通过调整生命周期或as_key()接口解决这个问题?这是否是相关技术文章中提到的问题变体?
编辑:将PartialEq约束放宽为HRTB for<'b> PartialEq<Self::Key<'b>>可以解决上面的Mutex示例,但会破坏泛型场景,比如以下实现无法编译:
struct NoKey<T>(T); impl<T> Value for NoKey<T> { type Key<'a> = () where T: 'a; fn as_key(&self) -> () { () } }
报错信息:
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
内容的提问来源于stack exchange,提问作者user4815162342
相关产品推荐
相关产品推荐

