我试图创建一个函数,给定回调,它可以对字符串执行一些操作,并且如果需要进行一些修改,则返回一个新分配的副本。我使用的是std:: borrow::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&模式= debug&版= 2021,要点= 8607 d8ac4c34d02236e82e30bcf51e2e
编译器报错,因为s
的生存期总是短于'a
所能提供的生存期。
要解决这个问题,可以使用更高级别的生命周期。在say_hello
函数中指定一个只适用于闭包的生命周期,而不是通用的生命周期。这是通过在impl
和Fn
之间添加for<'a>
来完成的。在此之后,say_hello
也不能返回Cow<'a, str>
,而需要返回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";
在这种情况下,您还可以依赖于生存期省略,并可选择使用占位符生存期'_
。然后变成:
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...
内联。