Rust 弦锈中F#的Cons图案的等效物

Rust 弦锈中F#的Cons图案的等效物,rust,tail,Rust,Tail,我正在通过实现我的一个小F#片段来试验生锈 我正处于要对字符串进行解构的位置。这是F#: 让rec内部检查acc=功能 |w::当Char.IsWhiteSpace(w)-> 内部检查acc尾部 |其他 |火柴 |这里 …可以这样调用:internalCheck[]“String here”其中:运算符表示右侧是“列表的其余部分” 因此,我查看了Rust文档,并提供了如下分解向量的示例: let v = vec![1,2,3]; match v { [] => ...

我正在通过实现我的一个小F#片段来试验生锈

我正处于要对字符串进行解构的位置。这是F#:

让rec内部检查acc=功能
|w::当Char.IsWhiteSpace(w)->
内部检查acc尾部
|其他
|火柴
|这里
…可以这样调用:
internalCheck[]“String here”
其中
运算符表示右侧是“列表的其余部分”

因此,我查看了Rust文档,并提供了如下分解向量的示例:

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

match v {
    [] => ...
    [first, second, ..rest] => ...
}
……等等。然而,现在这是在
切片模式
特征门之后。我试过类似的方法:

match input.chars() {
    [w, ..] => ...
}
这告诉我特性门需要非稳定版本才能使用

因此,我下载了
multirust
,并安装了我能找到的最新版本(
2016-01-05
),当我最终获得
slice\u patterns
功能时。。。关于语法和“rest”(在上面的例子中)不被允许,我遇到了无数的错误

那么,有没有一种等效的方法可以利用类似于
的功能来解构字符串。。。锈迹斑斑?基本上,我想将一个字符与一个守卫匹配,并在下面的表达式中使用“其他所有内容”

如果答案是“不,没有”,这是完全可以接受的。当然,我在任何地方都找不到这种类型的例子,切片模式匹配在功能列表中似乎也不高


(如果我在Rust文档中遗漏了什么,我会很高兴地删除这个问题)

我不这么认为。切片模式也不太可能适应这种情况,因为模式的“和其余”部分位于数组模式内部,这意味着某种方式可以将所述模式放入字符串中,这意味着一种不存在的转义机制


此外,Rust没有合适的“连接”操作符,并且它所拥有的操作符不能参与解构。所以,我不会为这件事屏住呼吸。

就在这里发布这件事。。。它似乎做了我想做的事。作为一个简单的测试,这将只打印字符串中的每个字符,但在找到空白字符时打印
找到空白字符
。它以递归方式执行此操作,并对字节向量进行解构。我必须向@ArtemGr大喊一声,他给了我灵感,让我研究如何使用字节,看看这是否解决了我在
char
s中遇到的编译器问题

毫无疑问,在这里我还没有意识到内存问题(复制/分配等;尤其是
字符串
实例)。。。但我会在深入研究锈迹的内部机理的同时,对其进行研究。它也可能比它需要的要详细得多。。这正是我修修补补后的结果

#![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空间中的字符。。所以现在这已经足够了


我想,要处理更宽的字符,锈迹模式匹配需要能够键入强制(我不相信您目前可以这么做?),因为
Chars可以将模式匹配与
字节
切片一起使用:

#![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标量值):

您还可以使用迭代器在Unicode标量值边界上拆分
&str

fn internal_check(acc: &str) -> bool {
    let mut chars = acc.chars();
    match chars.next() {
        Some('-') => internal_check(chars.as_str()),
        Some(ch) if ch.is_whitespace() => internal_check(chars.as_str()),
        None => true,
        _ => false,
    }
}

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

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

似乎对我有用:。也许语法已经改变了?仍然值得一个完整的答案。@ArtemGr是的,对不起,这似乎有效。然而,我似乎无法让它在字符串上工作。这就是问题的重点(如果不清楚的话,我应该重新措辞吗?)。顺便说一句@ArtemGr,谢谢你提供的操场链接-我不知道Rust有这样的操场(拇指支撑)。怎么样?游乐场似乎有一个暂时的问题,但在我的工作站上,它打印“匹配…1匹配…2”;看得很公平。这是我在F#中喜欢的一个特性,所以我确实希望它在Rust中是可能的。尽管如此,这并不能阻止我调查锈病。。。所以谢谢你:)+1去那里。除非您只使用ASCII,否则我认为您需要使用
&[char]
切片,唯一的瓶颈是从
&str
高效地获取它。我本来会使用堆栈分配的数组()的,但这是另一回事。这太棒了!我真的很感激你花了这么多时间来整理这件事。你的样本中有100件东西(包括工作和非工作)我可以从中学习。你有贡献。。我将来肯定能胜任这项任务。。一旦我对生锈感到更舒服了。再次感谢!我真的很感激!不客气!)另外,我已经在本地检查了这个答案中的所有样本,所有样本都应该有效。如果其中一些不适合您,请告诉我。由于LLVM相关的困难,也因为TCO使堆栈跟踪看起来不一样。IIRC,关键字
been
保留用于选择未来的TCO。我意识到我从未接受过你的回答@ArtemGr。对此表示歉意。@SimonWhitehead NP!)
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));
    }
}
fn internal_check(acc: &str) -> bool {
    let mut chars = acc.chars();
    match chars.next() {
        Some('-') => internal_check(chars.as_str()),
        Some(ch) if ch.is_whitespace() => internal_check(chars.as_str()),
        None => true,
        _ => false,
    }
}

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