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

标签 reference rust iterator borrow-checker ownership

我正在使用一个特征和一个返回盒装迭代器的方法。由于迭代器将使用 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 函数的巧妙方法?

最佳答案

实际上,在处理我的最小示例时,我想出了一个(某种程度上)解决问题的想法。可用in the playground .

想法是将 foo 的参数和返回的迭代器包装在一个专用类型中,它本身通过委托(delegate)给内部迭代器来实现 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))
}

不过,由于以下原因,我对该解决方案并不完全满意。

  • 对于这个特定的方法来说是相当具体的;对于具有其他参数的另一种方法,我需要不同的包装器类型。

  • 它使用了不安全的代码。我相信这个没问题(因为 String 的内部 &str 通过移动是稳定的),但它可能更难(如果不是不可能的话)用其他类型实现。

  • 它迫使我重新实现Iterator。虽然这个最小版本有效,但它不是最优的,因为底层迭代器可能已经优化了某些方法的实现,我在这里通过依赖默认实现来“松散”。手动实现 Iterator 的所有方法(将它们传递给 self.1)既乏味又脆弱(如果以后的版本添加新方法,我将不得不添加它们以及)。

所以仍然欢迎任何更好的解决方案...

编辑:@Shepmaster 的论点说服了我;这实际上是存储值和对它的引用的老问题。所以它不安全的,我的解决方案不是通用的,因为一般来说,它可能行不通:-/

关于reference - 我可以将局部变量的所有权和对它们的引用转移到返回的迭代器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54715300/

相关文章:

c++11 - 为什么 std::back_inserter 迭代器在范围 3 中不是弱增量的?

rust - 如何使用 Rust 中的 C typedef 结构和该结构的函数?

c# - 添加引用对话框中的程序集是否因使用的 .Net 框架而异?

c# - .dll 文件不可访问

php - 通过 __get() 通过引用返回 null

struct - 使用单元结构的真实示例是什么?

rust - 为什么在使用 TryFuture 而不是等效的 Future 时会收到有关类型不匹配的错误?

iterator - 使用 Iterable 和 Iterator 角色实现可迭代类

python - 在两个不同大小的列表上迭代时处理 StopIteration 异常

python - 如何在Python中使用字典作为字典的键