我有点失去理智了。
我想表达一个特征,保证类型能够从与引用 ('a) 一样长的引用 (&'a self) 创建另一个类型“Item”,但该类型的所有版本我可以成功地实现似乎在通用函数中失败的功能。
我将提供我在测试中尝试过的不同因式分解的简化版本,它们都会生成与我的完整代码相同的错误。 Tldr在底部。
我在代码中表达这一点的首选方式是:
trait T {
type Item<'a> where Self: 'a;
type Error;
fn f<'a>(&'a mut self) -> Result<Self::Item<'a>, Self::Error>;
}
因为它包含重要位置的生命周期,并且不会用不必要的生命周期着色来污染错误类型(或任何其他数据)。 (如果我在代码中的某个位置仅使用特征 T 作为错误类型,我不想添加无意义的生命周期)。
此代码很容易成功实现(我将使用虚拟类型进行演示)
struct S(i32)
impl T for S {
type Item<'a> = &'a i32;
type Error = Infallible;
fn f<'a>(&'a mut self) -> Result<Self::Item<'a>, Self::Error> {
Ok(&self.0)
}
}
但它在泛型方面有一个奇怪的问题。 这有效:
fn g<X: T>(x: X)->Option<()> {
let item = x.f().ok()?;
Some(())
}
但指定该项目不会:
fn f<'a, X: T<Item<'a> = &'a i32> + 'a>(x: X)->Option<()> {
let item = x.f().ok()?;
let y = item + 1;
Some(())
}
--参数要求借用
x
表示“'a”
--
x
丢在这里[fn 的结尾],同时仍然借用[不,不是吗?]
我真的不知道为什么这个不起作用
此分解在泛型中有效,但不可能实现,因为描述类型“Item”所需的生命周期“'a”不受特征或实现的约束
trait U {
type Item;
type Error;
fn f(&'a mut self) -> Result<Self::Item, Self::Error>;
}
将生命周期和/或项目类型移动到特征参数的因子如果在“f”签名中包含“a生命周期”,则具有与“T”相同的问题,但否则与“U”有相同的问题。
trait V1<'a, Item> {
type Error;
fn f(&'a self) -> Result<Item, Self::Error>;
} //Same as T
trait V2<'a, Item> {
type Error;
fn f(&self) -> Result<Item, Self::Error>;
} //Same as U
您可能已经注意到这一切与“TryFrom”非常相似,并且想知道我是否尝试将该特征表达为它的变体。我做到了。
trait W<'a> where Self: 'a {
type Item: TryFrom<&'a Self>;
fn f(&'a self) -> Result<Self::Item, <Self::Item as TryFrom<&'a Self>>::Error>
{<Self::Item as TryFrom<&'a Self>>::try_from(self)}
}
这是可以实现的,但是它在 fn“f”中给出了一个非常奇怪的错误。
fn f<'a, X: W<'a, Item = &'a i32> + 'a>(x: X)->Option<()>
{
let item = x.f().ok()?;
let y = item + 1;
Some(())
}
--特征界限
&'a i32: From<&'a X>
不满足
[哪个界限既不必要又保证实现。]
--特质
From<&'a X>
没有为 &'a i32
实现,这是 &'a i32: TryFrom<&'a X>
所要求的 [不,它不是也不可能是?]
(我也尝试将其显式添加到参数中,但仍然给出相同的错误。)
我迷路了。特别是,我没有得到特征 T 和 W 的错误,它们是最合理构建的,而不是 U、V1 和 V2,它们实际上只是黑客工作。我还进行了 4 项其他重构,但我没有包括在内。应该注意的是,这个特征基本上是我之前制作的迭代器特征(“I”)的开放版本,因此 I
这可以通过更高排名的特征界限来解决。
pub fn f<X: for<'a> T<Item<'a> = &'a i32>>(mut x: X) -> Option<()> {
let item = x.f().ok()?;
let y = item + 1;
Some(())
}
普通的生命周期参数只能属于函数外部的引用,但是这里的
&mut self
完全包含在函数内部。调用者无法提供此生命周期,因此 HRTB 需要 X
为每个生命周期实现 T
。