给定一个变量tokens: &Vec<String>
,我想执行以下操作:
- 验证它:有效的
tokens
必须以"abc"
、"def"
开头,以"xyz"
结尾(类型为co-rsedly speaking?(,并且相等不区分大小写 - 在有效的
tokens
的情况下,提取tokens
的其余部分以供以后处理
我尝试了什么:
fn process_tokens(tokens: &Vec<String>) -> Result<(), &str> {
let lowercased_tokens: Vec<String> = tokens.iter().map(|s| s.to_lowercase()).collect();
match lowercased_tokens.iter().map(|s| s as &str).collect::<Vec<_>>().as_slice() {
["abc", "def", remaining_tokens @ .., "xyz"] => {
// do something with remaining_tokens
Ok(())
}
_ => Err ("Invalid tokens!")
}
}
我的问题是:
- 创建了一个临时矢量
lowercased_tokens
,这在性能方面似乎并不理想 - 详细
然而,我很难找到如何在没有的情况下实现我想要的目标
- 在没有临时向量的情况下,在方法链接中生成的低位标记是"0";临时的";并且我们不能将CCD_ 9应用于它们
- 在另一个方向上,我不知道如何对
Vec<String>
进行模式匹配,即在匹配模式中放置"abc".to_string()
而不是"abc"
(这是无效语法(
我的建议是使用一片字符串(&[String]
(1,因为您可以"剥离";您正在验证的元素。我们可以将其概括为两个函数:一个在开始时期望某个东西,另一个在结束时期待某个东西。可以不区分大小写地进行比较,以防止分配额外的字符串。这两个函数都将返回一个子切片,其中删除了预期的元素。
这样做不需要额外的分配,因为切片只是向量自己分配的一个胖指针。
fn expect_start<'a>(expected: &'_ str, strs: &'a [String])
-> Result<&'a [String], &'static str>
{
match strs.first() {
Some(v) if expected.eq_ignore_ascii_case(v) => Ok(&strs[1..]),
_ => Err("unexpected token at start of string"),
}
}
fn expect_end<'a>(expected: &'_ str, strs: &'a [String])
-> Result<&'a [String], &'static str>
{
match strs.last() {
Some(v) if expected.eq_ignore_ascii_case(v) => Ok(&strs[..(strs.len() - 1)]),
_ => Err("unexpected token at end of string"),
}
}
现在,我们可以很容易地将这些组合到process_tokens
函数中,每当我们遇到错误时(使用?
(,我们都会弹出:
fn process_tokens(mut tok: &[String]) -> Result<(), &'static str> {
tok = expect_start("abc", tok)?;
tok = expect_start("def", tok)?;
tok = expect_end("xyz", tok)?;
// Do something with tok
println!("Remaining tokens: {:?}", tok);
Ok(())
}
(游乐场(
1这些函数可以像String
一样容易地使用&str
,但接受&str
的切片将需要创建第二个向量来保存引用第一个向量中的字符串的切片。但是,您可以通过接受&[T]
来更改这些函数以接受String
或&str
的切片,其中T: Borrow<str>
,因为String
和&str
都实现了这一特性。