如何解决如何定义适配器特征,其中某些实现需要 &self 的生命周期?
我正在为不同的键值存储编写一组基准测试,并希望有一个可以在所有基准测试中使用的适配器特征,然后为每个键值存储实现它。
这对其中两个很有效。然而,第三个要求我在我的特质上添加一个生命周期,并且在与借阅检查员战斗了一整天后,我似乎仍然无法正确完成。
我已经把它提炼成这个最小的复制品:https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=54fec74cb70c63c03f25ec7a9dfc7e60
我不明白的是为什么 txn
上的借用比 benchmark()
的作用域寿命更长。在我看来,它应该只存在那一行。
如何定义 AdapterTransaction
trait 来解决这个问题,仍然允许实现选择自己的返回类型?
编辑
补充说我需要能够使用带有工厂特征的 AdapterTransaction
实现
解决方法
您的 first playground 中的主要问题是 &self
的生命周期与特征的通用生命周期相同。
pub trait AdapterTransaction<'a,T: AsRef<[u8]>> {
fn get(&'a self,key: &[u8]) -> Option<T>;
}
因为它们是相同的,所以它需要底层类型的借用至少与类型本身一样长。这不是真的,因为即使类型是拥有的,借用也只会在函数调用期间持续。在 benchmark<'a,...>()
中,生命周期 'a
由调用者选择,并且该函数中的借用不可能足够长。删除 'a
上的 benchmark
参数并将其替换为更高排名的特征边界 (playground) 本来可以快速修复。
fn benchmark<U: AsRef<[u8]>,T: for<'a> AdapterTransaction<'a,U>>(txn: T)
在此示例中,调用方不再选择 'a
,因此编译器可以自由地为调用使用有效的生命周期。
至于您问题的第二部分,traits 可以定义关联类型,这些类型可以根据实现而改变。您可以拥有一个具有关联 Output
的特征,该特征可以针对每个实现的类型进行更改。执行泛型参数与关联类型有很大不同,因为在前一种情况下,您可以为同一类型实现一个特征的多个泛型变体。 (例如,这就是 From<T>
的工作方式)。
pub trait AdapterTransaction<'a> {
type Output;
fn get(&'a self,key: &[u8]) -> Option<Self::Output>;
}
impl<'a> AdapterTransaction<'a> for AdapterImpl {
type Output = &'a [u8];
fn get(&'a self,key: &[u8]) -> Option<Self::Output> {
Some(self.txn.get(&key))
}
}
fn benchmark<T>(txn: T)
where
for<'a> T: AdapterTransaction<'a>,{
let _ = txn.get(&[]).unwrap();
}
编辑:我最初的一些假设并不准确,如果以不冲突的方式使用特征生命周期,则没有必要在 &'a Type 上实现。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。