字符串Rust中F#的Cons模式等价

时间:2016-01-08 00:33:25

标签: rust tail

我正在通过实现我的一个小型F#片段来试验Rust。

我正处于想要构造一串字符的位置。这是F#:

 let rec internalCheck acc = function
    | w :: tail when Char.IsWhiteSpace(w) -> 
        internalCheck acc tail
    | other
    | matches
    | here

..可以像这样调用:internalCheck [] "String here" ::运算符表示右侧是"列表的其余部分"。

所以我检查了Rust文档,并且有像这样的解构向量的例子:

let v = vec![1,2,3];

match v {
    [] => ...
    [first, second, ..rest] => ...
}

...等。但是现在它位于slice_patterns功能门的后面。我尝试过类似的东西:

match input.chars() {
    [w, ..] => ...
}

这告诉我功能门需要使用非稳定版本。

所以我下载了multirust并安装了我能找到的最新的夜晚(2016-01-05),当我最终得到slice_patterns功能时...我遇到了关于语法的无尽错误"其余" (在上面的例子中)不被允许。

那么,在Rust中使用:: - 类似的功能吗?是否有一种等效方法来构造一串字符?基本上我想将一个角色与一个守卫相匹配并使用"其他所有"在后面的表达式中。

如果答案是&#34>完全可以接受;不,没有&#t;#34;。我当然无法在任何地方找到这种在线的很多例子,切片模式匹配在功能列表中看起来并不高。

(如果在Rust文档中遗漏了一些内容,我将很乐意删除这个问题)

3 个答案:

答案 0 :(得分:6)

您可以使用与byte切片匹配的模式:

#![feature(slice_patterns)]

fn internal_check(acc: &[u8]) -> bool {
    match acc {
        &[b'-', ref tail..] => internal_check(tail),
        &[ch, ref tail..] if (ch as char).is_whitespace() => internal_check(tail),
        &[] => true,
        _ => false,
    }
}

fn main() {
    for s in ["foo", "bar", "   ", " - "].iter() {
        println!("text '{}', checks? {}", s, internal_check(s.as_bytes()));
    }
}

您可以将其与char切片一起使用(其中char是Unicode标量值):

#![feature(slice_patterns)]

fn internal_check(acc: &[char]) -> bool {
    match acc {
        &['-', ref tail..] => internal_check(tail),
        &[ch, ref tail..] if ch.is_whitespace() => internal_check(tail),
        &[] => true,
        _ => false,
    }
}

fn main() {
    for s in ["foo", "bar", "   ", " - "].iter() {
        println!("text '{}', checks? {}",
                 s, internal_check(&s.chars().collect::<Vec<char>>()));
    }
}

但截至目前,它并没有使用&str(生成E0308)。我认为这是最好的,因为&str既不在这里,也不在那里,它是一个byte切片,但Rust试图保证它是有效的UTF-8并尝试提醒您使用&str来处理unicode序列和字符而不是字节。因此,要有效地匹配&str我们必须明确使用as_bytes方法,基本上告诉Rust,我们知道我们正在做什么&#34;。

无论如何,这是我的阅读。如果您想深入挖掘Rust编译器的源代码,可以从issue 1844开始,浏览那里链接的提交和问题。

  

基本上我想将1个角色与守卫相匹配并使用&#34;一切   别的&#34;在后面的表达式中。

如果您只想匹配单个字符,那么使用chars迭代器来获取字符并匹配字符本身可能比转换整个UTF-8更好{ {1}}进入&str切片。例如,使用chars迭代器,您不必为字符数组分配内存。

&[char]

您还可以使用chars迭代器在Unicode标量值边界上拆分fn internal_check(acc: &str) -> bool { for ch in acc.chars() { match ch { '-' => (), ch if ch.is_whitespace() => (), _ => return false, } } return true; } fn main() { for s in ["foo", "bar", " ", " - "].iter() { println!("text '{}', checks? {}", s, internal_check(s)); } }

&str

但请记住,截至目前,Rust并未保证将此尾递归函数优化为循环。 (尾部调用优化将成为该语言的一个受欢迎的补充,但由于与LLVM相关的困难,它目前尚未实现。)

答案 1 :(得分:2)

我不相信。切片模式也不太可能适用于此,因为模式的“和其余”部分 in 数组模式,这意味着某种方式放置所述模式字符串里面,这意味着一个不存在的转义机制。

此外,Rust没有合适的“连接”运算符, 所拥有的运算符不能参与解构。所以,我不会屏住呼吸这个。

答案 2 :(得分:1)

在这里张贴这个......它似乎做了我想要的。作为一个简单的测试,这将只打印字符串中的每个字符,但在找到空白字符时打印Found a whitespace character。它以递归方式执行此操作并对字节向量进行解构。我必须向@ArtemGr大声喊叫,他给了我灵感来看看使用字节来查看是否修复了我在char s时遇到的编译器问题。

毫无疑问,我在这里还没有意识到的内存问题(复制/分配等;特别是在String个实例周围)......但是当我深入研究时,我会对这些问题进行研究对Rust的内部运作。它可能也比它需要的要冗长得多......这就是我在经过一点修补之后所处的地方。

#![feature(slice_patterns)]

use std::iter::FromIterator;
use std::vec::Vec;

fn main() {
    process("Hello world!".to_string());
}

fn process(input: String) {
    match input.as_bytes() {
        &[c, ref _rest..] if (c as char).is_whitespace() => { println!("Found a whitespace character"); process(string_from_rest(_rest)) },
        &[c, ref _rest..] => { println!("{}", c as char); process(string_from_rest(_rest)) },
        _ => ()
    }
}

fn string_from_rest(rest: &[u8]) -> String {
    String::from_utf8(Vec::from_iter(rest.iter().cloned())).unwrap()
}

输出:

H
e
l
l
o
Found a whitespace character
w
o
r
l
d
!

显然,作为对单个字节的测试(并且在重建字符串时仅考虑可能的UTF-8字符),它不适用于宽字符。我的实际用例只需要ASCII空间中的字符..所以现在就足够了。

我想,为了处理更广泛的字符,Rust模式匹配需要能够输入强制(我不相信你现在可以做什么?),因为似乎推断出Chars<'T>迭代器为&[_]。在我的其他尝试中,这可能只是我对Rust语言的不成熟。