我正在通过实现我的一个小型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文档中遗漏了一些内容,我将很乐意删除这个问题)
答案 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;。
基本上我想将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语言的不成熟。