rust - 如何在Rust中将IntoIterator <Item = AsRef <str >>转换为Iterator <Item =&str>?

标签 rust

我每晚运行Rust(rustc 1.50.0-nightly (f0f68778f 2020-12-09))。
我了解了一种接受(作为函数参数)可以转换为迭代器的任意对象的方法。我还学习了一种方法,该方法允许使用String接受&str&str(可能还可以接受其他类型的可以转换为AsRef<str>的类型)。
到目前为止,我已经提供了以下测试代码来证明这一点:

use std::env;

fn main() {
    let v1: Vec<String> = vec!["a".to_string(), "b".to_string()];
    let v2: Vec<&str> = vec!["a", "b"];
    let args: env::Args = env::args();

    fun1(&v1);
    fun1(&v2);

    fun1(v1);
    fun1(v2);
    fun1(args);
}

fn fun1<I, T>(args: I)
where
    I: IntoIterator<Item = T>,
    T: AsRef<str>,
{
    println!("=================");
    for item in args {
        println!("{}", item.as_ref());
    }
}
它可以很好地编译并且运行良好。现在,我的愿望是将argsIntoIterator<Item=AsRef<str>>转换为Iterator<Item=&str>,这样我就不必在整个函数中处理那些as_ref()调用。在此示例中,这是一个简单的循环,它在一个地方调用as_ref(),但是我在这里不共享的代码更加复杂-我想避免每次从该迭代器中获取下一个元素时都调用as_ref()
不幸的是,我这样做的天真尝试是行不通的:
use std::env;

fn main() {
    let v1: Vec<String> = vec!["a".to_string(), "b".to_string()];
    let v2: Vec<&str> = vec!["a", "b"];
    let args: env::Args = env::args();

    fun2(&v1);
    fun2(&v2);

    fun2(v1);
    fun2(v2);
    fun2(args);
}

fn fun2<I, T>(args: I)
where
    I: IntoIterator<Item = T>,
    T: AsRef<str>,
{
    println!("=================");
    let iter = args.into_iter();
    let mapped = iter.map(|item| item.as_ref());
    for item in mapped {
        println!("{}", item);
    }
}
% rustc test1.rs 
error[E0515]: cannot return value referencing function parameter `item`
  --> test1.rs:23:34
   |
23 |     let mapped = iter.map(|item| item.as_ref());
   |                                  ----^^^^^^^^^
   |                                  |
   |                                  returns a value referencing data owned by the current function
   |                                  `item` is borrowed here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0515`.
在我的一生中,我无法解决这个问题(我使用各种方法玩耍,而我所得到的只是像这样的错误),我仔细研究了之前的一些问题,但没有运气。
在Rust中甚至有办法实现这一目标吗?

最佳答案

如果不将迭代器中的所有数据收集到Vec或类似文件中,这是不可能的。这是因为Iterator<Item = &str>要求切片后面的字符串数据不归迭代器所有,但是Iterator<Item = String>确实通过使用拥有的类型来拥有字符串数据。
这也解释了为什么将向量收集为有效的原因。在那种情况下,字符串数据将由向量而不是迭代器拥有,这满足了Iterator<Item = &str>不拥有字符串数据的要求。

fn fun2<I, T>(args: I)
where
    I: IntoIterator<Item = T>,
    T: AsRef<str>,
{
    println!("=================");
    
    let vec: Vec<T> = args.into_iter().collect();
    
    let mapped = vec.iter().map(|item| item.as_ref());
    for item in mapped {
        println!("{}", item);
    }
}
请注意,并非总是T: AsRef<str>类型拥有字符串数据。例如,如果T = &str,则不是。不幸的是,通用代码必须处理通用参数所允许的所有情况,因此,如果代码不处理T = String情况,它将无法编译。
请注意,在T = &str的情况下,上述示例中的向量不拥有字符串数据。仍然可以,因为在这种情况下,字符串数据完全由fun2之外的其他某个集合拥有,并且还满足Iterator<Item = &str>一定不能拥有字符串数据的要求。

关于rust - 如何在Rust中将IntoIterator <Item = AsRef <str >>转换为Iterator <Item =&str>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65250496/

相关文章:

rust - 如何将值的所有权从 Rust 转移到 C 代码?

对于给定的 impl,rustc 可以是 "infer the appropriate lifetime",但不能用于另一个

rust - 为什么RuSTLings不强制我使用结果?

rust - 匹配 "if let Some(ref mut x) = option"和 "if let Some(x) = option.as_mut()"中的可变选项引用有什么区别?

c - 当我从 native C 代码调用 Rust dylib 时,底层会发生什么?

rust - PathBuf::deref() 如何返回对临时对象的引用?

rust - 如何将两个常量之一存储在一个值中,其中常量共享特征?

iterator - 如何跳过 Rust 中迭代器的前 n 项?

reference - 在 Vec 中混合引用的生命周期

rust - 如何使用自定义 libstd 进行构建?