如何定义一个 Rust 函数来使用一个拥有的 String 并返回一个拥有的 Split?

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

我想从标准输入读取一行,然后用空格分割它并处理这些部分。

一个简单的 read_line 就可以工作,因为它返回一个拥有的字符串:

fn read_line() -> String {
    let mut str: String = String::new();
    stdin().read_line(&mut str).unwrap();
    return str;
}

但是当我想使用 String 并返回一个拥有的 Split 时,我无法做到这一点,其生命周期超出了创建它的函数的范围。

rust
1个回答
0
投票

创建

Split
的自有版本比看起来更棘手。但如果你尝试显而易见的事情:

// doesn't compile
fn owned_split(s: String) -> impl Iterator<Item = String> {
    s.split_whitespace().map(|sub| sub.to_string())
}

这不会编译,因为

SplitWhitespace
返回的
s.split_whitespace()
想要保存对字符串的引用。这个
owned_split()
有效地返回了对本地的引用,它不会编译(也不应该编译)。理想情况下,我们会返回一个包含原始字符串和指向它的
SplitWhitespace
的结构,但这不起作用,因为借用检查器尚不支持自引用结构。可以使用 one of the 自引用板条箱使其在“安全”代码中工作,但让我们首先探索其他选项。

解决该问题的一个简单方法是在每个

split_whitespace()
上重新调用
next()
,并每次都返回“第一个”项目。这需要一些技巧来弄清楚在哪里继续调用它,但这是可以做到的:

fn owned_split(s: String) -> impl Iterator<Item = String> {
    let mut pos = 0;
    std::iter::from_fn(move || {
        let sub = s[pos..].split_whitespace().next()?;
        // next search position is at the end of `sub`
        pos = sub.as_bytes().as_ptr_range().end as usize - s.as_ptr() as usize;
        Some(sub.to_owned())
    })
}

游乐场

最后,这是一个使用 ouroboros 创建自引用结构的版本:

use std::str::SplitWhitespace;
use ouroboros::self_referencing;

fn owned_split(s: String) -> impl Iterator<Item = String> {
    #[self_referencing]
    struct OwnedSplit {
        owner: String,
        #[borrows(owner)]
        #[not_covariant]
        split: SplitWhitespace<'this>,
    }
    impl Iterator for OwnedSplit {
        type Item = String;
        fn next(&mut self) -> Option<String> {
            self.with_split_mut(|split| split.next().map(|s| s.to_owned()))
        }
    }
    OwnedSplit::new(s, |s| s.split_whitespace())
}
© www.soinside.com 2019 - 2024. All rights reserved.