Rust 中 F# 中字符串的等价 Cons 模式
Equivalent of Cons Pattern from F# in Rust for Strings
我正在通过实现我的一小段 F# 来试验 Rust。
我现在想解构一串字符。这是 F#:
let rec internalCheck acc = function
| w :: tail when Char.IsWhiteSpace(w) ->
internalCheck acc tail
| other
| matches
| here
..可以这样调用:internalCheck [] "String here"
其中 ::
运算符表示右侧是 "rest of the list".
所以我查看了 Rust 文档,有像这样解构向量的示例:
let v = vec![1,2,3];
match v {
[] => ...
[first, second, ..rest] => ...
}
..等然而,这现在位于 slice_patterns
功能门之后。我试过类似的东西:
match input.chars() {
[w, ..] => ...
}
这告诉我功能门需要非稳定版本才能使用。
所以我下载了 multirust
并安装了我能找到的最新版本 (2016-01-05
),当我终于让 slice_patterns
功能正常工作时......我 运行关于语法和"rest"(在上面的例子中)的无尽错误是不允许的。
那么,在 Rust 中是否有一种等效的方法来解构字符串,利用类似于 ::
的功能……?基本上我想将 1 个字符与守卫匹配并在后面的表达式中使用 "everything else"。
如果答案是"No, there isn't"完全可以接受。我当然无法在任何地方在线找到很多此类示例,而且切片模式匹配在功能列表中似乎并不重要。
(如果我在 Rust 文档中遗漏了什么,我会很乐意删除这个问题)
我不这么认为。切片模式也不太可能适用于此,因为模式的 "and the rest" 部分进入 inside 数组模式,这意味着以某种方式放置所述模式里面一个字符串,这意味着不存在的转义机制。
此外,Rust 没有合适的 "concatenation" 操作符,它 有的操作符 不能参与解构。所以,我不会在这个问题上屏住呼吸。
只是去 post 这里...它似乎做我想做的事。作为一个简单的测试,这将只打印字符串中的每个字符,但在找到白色 space 字符时打印 Found a whitespace character
。它递归地执行此操作并解构字节向量。我必须向@ArtemGr 大声喊叫,他给了我灵感来研究使用字节,看看它是否解决了我在 char
s.
中遇到的编译器问题
毫无疑问,我在这里还没有意识到内存问题(copying/allocations,等等;尤其是在 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 space 中的字符 .. 所以现在就足够了。
我想,要处理更宽的字符,Rust 模式匹配需要能够键入强制(我不相信你目前可以这样做?),因为 Chars<'T>
迭代器似乎是推断出来的作为 &[_]
。这可能只是我在其他尝试中对 Rust 语言的不成熟。
您可以将模式匹配与 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 "we know what we're doing".
无论如何,这就是我的阅读。如果您想更深入地研究 Rust 编译器的源代码,您可以从 issue 1844 开始并浏览那里链接的提交和问题。
Basically I want to match 1 character with a guard and use "everything
else" in the expression that follows.
如果您只想匹配 单个 字符,则使用 chars iterator to get the characters and matching on the character itself might be better than converting the entire UTF-8 &str
into a &[char]
slice. For instance, with the chars 迭代器,您不必为字符数组分配内存。
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));
}
}
您还可以使用 chars 迭代器在 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 无法保证将此 tail-recursive 函数优化为循环。 (尾调用优化本来是该语言的一个受欢迎的补充,但由于 LLVM-related 困难,目前尚未实施)。
我正在通过实现我的一小段 F# 来试验 Rust。
我现在想解构一串字符。这是 F#:
let rec internalCheck acc = function
| w :: tail when Char.IsWhiteSpace(w) ->
internalCheck acc tail
| other
| matches
| here
..可以这样调用:internalCheck [] "String here"
其中 ::
运算符表示右侧是 "rest of the list".
所以我查看了 Rust 文档,有像这样解构向量的示例:
let v = vec![1,2,3];
match v {
[] => ...
[first, second, ..rest] => ...
}
..等然而,这现在位于 slice_patterns
功能门之后。我试过类似的东西:
match input.chars() {
[w, ..] => ...
}
这告诉我功能门需要非稳定版本才能使用。
所以我下载了 multirust
并安装了我能找到的最新版本 (2016-01-05
),当我终于让 slice_patterns
功能正常工作时......我 运行关于语法和"rest"(在上面的例子中)的无尽错误是不允许的。
那么,在 Rust 中是否有一种等效的方法来解构字符串,利用类似于 ::
的功能……?基本上我想将 1 个字符与守卫匹配并在后面的表达式中使用 "everything else"。
如果答案是"No, there isn't"完全可以接受。我当然无法在任何地方在线找到很多此类示例,而且切片模式匹配在功能列表中似乎并不重要。
(如果我在 Rust 文档中遗漏了什么,我会很乐意删除这个问题)
我不这么认为。切片模式也不太可能适用于此,因为模式的 "and the rest" 部分进入 inside 数组模式,这意味着以某种方式放置所述模式里面一个字符串,这意味着不存在的转义机制。
此外,Rust 没有合适的 "concatenation" 操作符,它 有的操作符 不能参与解构。所以,我不会在这个问题上屏住呼吸。
只是去 post 这里...它似乎做我想做的事。作为一个简单的测试,这将只打印字符串中的每个字符,但在找到白色 space 字符时打印 Found a whitespace character
。它递归地执行此操作并解构字节向量。我必须向@ArtemGr 大声喊叫,他给了我灵感来研究使用字节,看看它是否解决了我在 char
s.
毫无疑问,我在这里还没有意识到内存问题(copying/allocations,等等;尤其是在 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 space 中的字符 .. 所以现在就足够了。
我想,要处理更宽的字符,Rust 模式匹配需要能够键入强制(我不相信你目前可以这样做?),因为 Chars<'T>
迭代器似乎是推断出来的作为 &[_]
。这可能只是我在其他尝试中对 Rust 语言的不成熟。
您可以将模式匹配与 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 "we know what we're doing".
无论如何,这就是我的阅读。如果您想更深入地研究 Rust 编译器的源代码,您可以从 issue 1844 开始并浏览那里链接的提交和问题。
Basically I want to match 1 character with a guard and use "everything else" in the expression that follows.
如果您只想匹配 单个 字符,则使用 chars iterator to get the characters and matching on the character itself might be better than converting the entire UTF-8 &str
into a &[char]
slice. For instance, with the chars 迭代器,您不必为字符数组分配内存。
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));
}
}
您还可以使用 chars 迭代器在 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 无法保证将此 tail-recursive 函数优化为循环。 (尾调用优化本来是该语言的一个受欢迎的补充,但由于 LLVM-related 困难,目前尚未实施)。