为什么一个通用函数中需要“预期的命名生命周期参数”

4
如果我写了这样的一个函数:
fn parse_json<'a, T: Deserialize<'a>>(s: &'a str) -> Vec<T> {
    serde_json::from_str(s).unwrap()
}

它按预期工作。 但是,如果我尝试不显式声明生命周期进行相同的操作,就像这样:

fn parse_json<T: Deserialize>(s: &str) -> Vec<T> {
    serde_json::from_str(s).unwrap()
}

我遇到了编译器错误:

| fn parse_json<T: Deserialize>(s: &str) -> Vec<T> {
|                  ^^^^^^^^^^^ expected named lifetime parameter

为什么?编译器在这种情况下要求显式生命周期声明,是否有原因?

如果我使用的不是泛型而是具体类型,则不需要明确声明任何生命周期:

fn parse_json(s: &str) -> Vec<MyStruct>   // that compiles file

我认为这是由于所谓的 生命周期省略规则导致的。问题是,为什么具有通用返回类型的版本也不受省略规则的覆盖呢?


2
因为编译器还没有猜到它。 - Stargateur
由于生命周期省略规则仅适用于 _引用_,而不适用于泛型参数,所以您必须编写 Deserialze<'a>。此时,您还必须说明引用的生命周期与泛型参数相同,因此也需要显式地声明它们。 - Jmb
1
@Jmb 看起来它也适用于其他类型的生命周期,例如 这段代码可以编译通过,尽管 MyStruct 不是一个引用。 - user4815162342
1个回答

2
生命周期省略适用于函数参数和返回类型,但目前不适用于特质约束,比如 T: Deserialize
为什么?编译器要求在这种情况下需要显式声明生命周期是否有原因吗?
我不确定,但总的来说,生命周期省略规则相当受限制,可能是为了使它们易于理解,并减少引入混乱的编译器“魔法”的机会。
请注意,生命周期省略确实支持泛型参数,但它已经半废弃了(参见elided_lifetimes_in_paths lint):
struct Foo<'a>(&'a str);

// Compiles, but causes a warning with `#![warn(rust_2018_idioms)]`
fn bar1(s: &str) -> Foo { Foo(s) }

// Compiles, does not cause warning
fn bar2(s: &str) -> Foo<'_> { Foo(s) }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接