Rust 参考在此处被删除,同时仍被借用

Jus*_*sch 5 lifetime rust

问题:我从一个方法中得到一个“XXXXXXX 下降到这里仍然借用”错误,其中 XXXXXXX 在方法结束时有效(这很好),但是 Rust 不必要地期望它只要输入引用就可以存活因为那些有明确的生命周期。

这是一些设置信息:我有一个结构体,它在文本内容中迭代所有找到的查询。

pub struct QueryRangeItr<'a> {
    inverted: bool,
    query: &'a str,
    content: &'a str,
}
Run Code Online (Sandbox Code Playgroud)

它需要查询和内容的引用,并期望实例与查询/内容一样长。到现在为止还挺好。

impl<'a> QueryRangeItr<'a> {
    fn new(query: &'a str, content: &'a str, inverted: bool) -> QueryRangeItr<'a> {
        Self {
            inverted,
            query,
            content,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个静态方法,允许您对每个找到的查询执行转换。它接受一个闭包并将其应用于查询,然后为您提供一个String没有生命周期依赖的 new 。因为返回值没有生命周期,我实际上并不在这里为查询和内容带来生命周期,但如果我不这样做,Rust 告诉我我需要......因此,它们有生命周期要求。就其本身而言,这很好用。

问题发生在另一个静态方法上,该方法调用transform两次以转换查询非查询内容。它首先调用transfrom对找到的查询应用一个闭包。结果将反馈到该transform方法的另一个调用,但这次将转换应用于其余内容。

impl<'a> QueryRangeItr<'a> {
    pub fn transform<T>(
        query: &'a str,
        content: &'a str,
        transform: T,
        inverted: bool,
    ) -> String where T: Fn(&str) -> String {
        let selects = Self::new(query, content, true);
        // ...
        // returns a `String` with no lifetime dependency on input params
    }

    pub fn transform_all<TQ, TNQ>(
        query: &'a str,
        content: &'a str,
        transform_query: TQ,
        transform_non_query: TNQ,
    ) -> String
        where
            TQ: Fn(&str) -> String,
            TNQ: Fn(&str) -> String,
    {
        let transformed_content = Self::transform(query, content, &transform_query, false);
        let transformed_query = transform_query(query);
        let transformed = Self::transform(&transformed_query, &transformed_content, transform_non_query, true); // <--- Rust expects `transformed_content` and `transformed_query` to match the lifetime of `query` and `content`
        transformed
    }

}
Run Code Online (Sandbox Code Playgroud)

transformed_content并且transformed_query两者都在transform_all......结束时死亡,这是有道理的,但 Rust 希望它们与输入参数querycontent('a)...一样长,而不会。

实际上不需要他们再活下去了。一旦我transformed回来,我就不再需要它们了。然而,有生命周期querycontent让 Rust 认为它们需要比实际需要的时间更长,我得到了这个错误:

115 | impl<'a> QueryRangeItr<'a> {
    |      -- lifetime `'a` defined here
...
200 |         let transformed = Self::transform(&transformed_query, &transformed_content, transform_non_query, true);
    |                           ------------------------------------^^^^^^^^^^^^^^^^^^^^----------------------------
    |                           |                                   |
    |                           |                                   borrowed value does not live long enough
    |                           argument requires that `transformed_content` is borrowed for `'a`
201 |         transformed
202 |     }
    |     - `transformed_content` dropped here while still borrowed
Run Code Online (Sandbox Code Playgroud)

如果我删除生命周期,我会收到此错误:

error[E0621]: explicit lifetime required in the type of `query`
   --> src/range/query_range_iterator.rs:130:23
    |
125 |         query: &str,
    |                ---- help: add explicit lifetime `'a` to the type of `query`: `&'a str`
...
130 |         let selects = Self::new(query, content, invert);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
Run Code Online (Sandbox Code Playgroud)

而且,如果我尝试为我的转换方法定义一个不同的生命周期'a'b'_),我会得到这样的结果:

error[E0521]: borrowed data escapes outside of associated function
   --> src/range/query_range_iterator.rs:130:23
    |
126 |         content: &'_ str,
    |         ------- `content` is a reference that is only valid in the associated function body
...
130 |         let selects = Self::new(query, content, invert);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `content` escapes the associated function body here
Run Code Online (Sandbox Code Playgroud)

我想要做的是找到一种方法来向 Rust 证明我不需要transformed_contenttransformed_query只要它认为。

有什么想法吗?

kmd*_*eko 5

代替

 = Self::transform(&transformed_query, &transformed_content, ...
// ^^^^
Run Code Online (Sandbox Code Playgroud)

 = QueryRangeItr::transform(&transformed_query, &transformed_content, ...
// ^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

通过使用Self,您'a对所有内容都使用相同的生命周期。正如您所指出的,transformed_content并且transformed_query只存在于函数中,因此它们的生命周期肯定更短并且无法匹配'a. 替换SelfQueryRangeItr允许编译器'a为调用选择一个新的生命周期。