【问题标题】:How to manage lifetime through callbacks如何通过回调管理生命周期
【发布时间】:2021-10-29 20:32:48
【问题描述】:

我正在尝试创建一个函数,给定一个回调,它可以对字符串执行一些操作,并且如果它需要一些修改,则返回一个新分配的副本。我正在使用 std::borow::Cow 来处理这样的事情,但是当我尝试使用回调来更改对字符串执行该操作的方式时,问题就来了。

这是我正在尝试做的一个简化示例:

use std::borrow::Cow;
pub enum Error {
    Test,
}

fn do_lower_case<'a> (s: &'a str) -> Result<Cow<'a, str>, Error>
{   
    let s = s.to_lowercase();
    Ok(s.into())
}

fn say_hello<'a>(
    f: impl Fn(&'a str) -> Result<Cow<'a, str>, Error>,
) -> Result<Cow<'a, str>, Error> 
{   
    let s = String::from("Hello");

    // Problem: We can not call the callback from here.
    // Nevertheless we can call do_lower_case
    let s = f(&s)?; // Comment this and uncomment next line works
    //let s = do_lower_case(&s)?;

    let s = s.into_owned();
    Ok(s.into())
}

fn main() {
    let res = say_hello(do_lower_case); // Callback is provided here
    match res {
        Ok(s) => println!("Result: {}", s),
        Err(_) => println!("Could not do anything!"),
    }
}

这样的事情可以在 Rust 中完成吗? 这是一个生锈游乐场的链接: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8607d8ac4c34d02236e82e30bcf51e2e

【问题讨论】:

    标签: rust callback lifetime


    【解决方案1】:

    编译器抱怨,因为s 的生命周期总是比'a 可以提供的生命周期短。

    要解决此问题,您可以使用higher-ranked lifetimes。您可以指定一个仅适用于闭包的生命周期,而不是 say_hello 函数中的通用生命周期。这是通过在implFn 之间添加for&lt;'a&gt; 来完成的。之后say_hello也不能返回Cow&lt;'a, str&gt;,需要返回String

    fn say_hello(f: impl for<'a> Fn(&'a str) -> Result<Cow<'a, str>, Error>) -> Result<String, Error> {
        let s = "Hello";
        let s = f(&s)?;
        let s = s.into_owned();
        Ok(s)
    }
    

    或者,以下内容可能更具可读性:

    fn say_hello<F>(f: F) -> Result<String, Error>
    where
        F: for<'a> Fn(&'a str) -> Result<Cow<'a, str>, Error>,
    {
        let s = "Hello";
        let s = f(&s)?;
        let s = s.into_owned();
        Ok(s)
    }
    

    也将let s = String::from("Hello"); 更改为let s = "Hello";


    在这种情况下,您还可以依赖lifetime elision 并选择使用占位符生存期'_。然后就变成了:

    fn say_hello<F>(f: F) -> Result<String, Error>
    where
        F: Fn(&str) -> Result<Cow<str>, Error>,
    {
    

    fn say_hello<F>(f: F) -> Result<String, Error>
    where
        F: Fn(&'_ str) -> Result<Cow<'_, str>, Error>,
    {
    

    您也可以像原来一样使用 impl Fn... 内联其中一个。

    【讨论】:

      猜你喜欢
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多