这个问题在这里已有答案:
我正在使用一个带有返回盒装迭代器的方法的特征。由于迭代器将使用self
和foo
的参数,所有都被约束到相同的生命周期:
pub trait Foo {
fn foo<'a>(&'a self, txt: &'a str) -> Box<Iterator<Item = String> + 'a>;
}
我想围绕这个方法构建一个函数:
fn foo_int<'a, F: Foo>(f: &'a F, val: i32) -> impl Iterator<Item = String> + 'a {
let txt = format!("{}", val);
f.foo(&txt)
}
但那不能编译,因为:
error[E0515]: cannot return value referencing local variable `txt`
--> src/lib.rs:7:5
|
7 | f.foo(&txt)
| ^^^^^^----^
| | |
| | `txt` is borrowed here
| returns a value referencing data owned by the current function
我理解为什么会发生这种情况,这是有道理的,但似乎应该有办法绕过它。毕竟,这就是闭包(使用move
关键字)所做的事情:他们拥有所需的价值,以“带走他们”。
是否有一种聪明的方法来重写foo_int
函数,使用闭包或其他东西?
实际上,在处理我的最小例子时,我想出了一种(某种程度上)解决问题的想法。它是可用的in the playground。
我们的想法是将foo
和返回的迭代器的参数包装在一个专用类型中,该类本身通过委托给内部迭代器来实现Iterator
特性。
pub struct Bar<'a>(String, Box<Iterator<Item = String> + 'a>);
impl<'a> Bar<'a> {
fn new<F: Foo>(foo: &'a F, txt: String) -> Bar<'a> {
let itr = foo.foo(unsafe { &*(&txt[..] as *const str) });
Bar(txt, itr)
}
}
impl<'a> Iterator for Bar<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.1.next()
}
}
fn foo_int<'a, F: Foo>(f: &'a F, val: i32) -> impl Iterator<Item = String> + 'a {
Bar::new(f, format!("{}", val))
}
但是,由于以下原因,我对这个解决方案并不完全满意。
&str
的内部String
通过移动是稳定的),但是用其他类型实现它可能更难(如果不是不可能的话)。Iterator
。虽然这个最小版本可以工作,但它不是最理想的,因为底层迭代器可能已经优化了某些方法的实现,我在这里依赖于默认实现“松散”。手动实现Iterator
的所有方法(将它们传递给self.1
)是乏味的,而且很脆弱(如果进一步的版本添加新的方法,我也必须添加它们)。所以任何更好的解决方案仍然受欢迎
编辑:@ Shepmaster的论点说服了我;这实际上是存储值和引用它的同样老问题。所以它是不安全的,我的解决方案不是一般的,因为一般来说,它可能不起作用: - /