我可以将局部变量的所有权和对它们的引用转移到返回的迭代器吗? [重复]

问题描述 投票:2回答:1

我正在使用一个带有返回盒装迭代器的方法的特征。由于迭代器将使用selffoo的参数,所有都被约束到相同的生命周期:

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函数,使用闭包或其他东西?

reference rust iterator borrow-checker ownership
1个回答
1
投票

实际上,在处理我的最小例子时,我想出了一种(某种程度上)解决问题的想法。它是可用的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的论点说服了我;这实际上是存储值和引用它的同样老问题。所以它是不安全的,我的解决方案不是一般的,因为一般来说,它可能不起作用: - /

© www.soinside.com 2019 - 2024. All rights reserved.