提问人:Xavier Detant 提问时间:7/7/2023 更新时间:7/8/2023 访问量:29
不匹配的类型:一种类型比另一种类型更通用,使用受约束的高等级特征边界
mismatched types : one type is more general than the other, using constrained Higher-Rank Trait Bounds
问:
这是“在借用时放在这里”的后续,在进行生命周期明确时,但可以独立查看。
既然@jthulhu让我发现了修复我之前错误的高级特征边界,我想通过概括它来更进一步。因此,让我们创建一个特征:
trait ToImplement {
type Arg<'arg>;
fn do_something<F>(&self, f: F)
where
F: for<'b> FnOnce(Self::Arg<'b>) -> ();
}
此特性可以毫无问题地实现,并且当直接使用时,可以按预期工作,如以下测试所示:
impl ToImplement for String {
type Arg<'arg> = &'arg str;
fn do_something<F, T>(&self, f: F) -> T
where
F: for<'b> FnOnce(Self::Arg<'b>) -> T,
{
f(&self)
}
}
#[test]
fn works() {
let hello = String::from("Hello");
let r = hello.do_something(|s| format!("{s} world!"));
assert_eq!(r,"Hello world!")
}
现在,让我们尝试编写一个函数,该函数在不知道实现者的情况下使用该方法,但知道对类型的一些约束,以便我们可以使用它。do_something
Arg
10 │ fn go<D, I>(implementor: I)
11 │ where
12 │ D: Display,
13 │ for<'a> I: ToImplement<Arg<'a> = D>,
14 │ {
15 │ implementor.do_something(|a| println!("{a}"));
16 │ }
这确实可以正确编译,但如果我们尝试像这样使用它:
33 │ #[test]
34 │ fn works() {
35 │ let hello = String::from("Hello");
36 │ go(hello);
37 │ }
然后我们得到这个错误:
error[E0308]: mismatched types
|
36 | go(hello);
| ^^^^^^^^^ one type is more general than the other
|
= note: expected reference `&'a str`
found reference `&str`
note: the lifetime requirement is introduced here
|
13 | for<'a> I: ToImplement<Arg<'a> = D>,
|
我认为我在第 13 行声明寿命的方式是错误的。但我不知道我还能怎么做。'a
我阅读了@jthulhu指出的关于所有权的rustonomicon章节,并认为借用拆分会给我一些答案,并查看了Take的实现,但没有更高等级的特征边界。
答:
1赞
Xavier Detant
7/8/2023
#1
经过大量挖掘,我最终在RFC中找到了一个解决方案:https://github.com/rust-lang/rfcs/blob/master/text/1598-generic_associated_types.md#using-associated-type-constructors-in-bounds
诀窍是像这样单独声明生存期:Arg
ToImplement
fn go<I>(implementor: I)
where
I: ToImplement,
for<'a> I::Arg<'a>: Display,
{
implementor.do_something(|a| println!("{a}"));
}
现在,它看起来像编译器作为推断类型的问题,因此我们必须在调用函数时定义它:
#[test]
fn works() {
let hello = String::from("Hello");
go::<String>(hello);
}
评论