解析是一个广泛而多样化的主题。有简单易用的解析工具,也有高性能的解析工具以及介于两者之间的一系列工具。
fn main() {
let haystack = "HTTP/1.1 200\r\n";
let needle = "HTTP/1.";
let z: Option<u8> = haystack.rfind(needle).and_then(|pt| {
let after_match = &haystack[(pt + needle.len())..];
after_match.splitn(2, " ").next()
}).and_then(|val| {
val.parse().ok()
});
println!("{:?}", z)
}
在这里,我们使用
rfind
,就像之前一样,但有可能失败。我们使用
and_then
来运行闭包,如果结果为
Some
。第一个闭包在找到匹配字符串后切割该字符串,并在空格上以2个部分为最大值进行分割。这可能会失败,所以我们使用第二个
and_then
来使用
parse
,它也可能会以
Result
失败,因此我们将其转换为
Option
以保留类型。
在最后,我们仍然可能失败,因为我们解析的内容可能不是可解析的数字!
Rust 真的帮助您明确可以失败的位置,并且您必须处理它们。 ^_^
在这种情况下:
- 字符串中可能没有 "HTTP/1."
- 迭代器必须在某些点结束,因此它们可以返回
None
。
- 将字符串解析为数字可能失败。
以下是使用正则表达式包的另一种解决方案:
extern crate regex;
use regex::Regex;
fn main() {
let haystack = "HTTP/1.1 200\r\n";
let re = Regex::new(r"HTTP/1.(\d) (\d+)\r\n").unwrap();
let captures = re.captures(haystack).unwrap();
let version: Option<u8> = captures.at(1).and_then(|version| version.parse().ok());
let status: Option<u8> = captures.at(2).and_then(|version| version.parse().ok());
assert_eq!(Some(1), version);
assert_eq!(Some(200), status);
println!("Version: {:?}, Status: {:?}", version, status);
}
你会发现我们有相同的故障模式,但结构略有不同。
或者可能是使用 Result
和 try!
的版本:
#[derive(Debug,Copy,Clone,PartialEq)]
enum Error {
StartNotFound,
NotANumber,
}
fn parse_it(haystack: &str) -> Result<u8, Error> {
let needle = "HTTP/1.";
let pt = try!(haystack.rfind(needle).ok_or(Error::StartNotFound));
let after_match = &haystack[(pt + needle.len())..];
let val = after_match.splitn(2, " ").next().unwrap();
val.parse().map_err(|_| Error::NotANumber)
}
fn main() {
println!("{:?}", parse_it("HTTP/1.1 200\r\n"));
println!("{:?}", parse_it("HTTP/1"));
println!("{:?}", parse_it("HTTP/1.cow"));
}
match
语句重写它,或者从Option
升级到Result
,然后利用try!
宏。我已经添加了这个和一个正则表达式示例。我不能代表整个Rust社区,但你应该编写自己能够理解的代码!“每个人都知道调试比一开始编写程序要难两倍。所以如果你在编写时越聪明,那么你将如何调试呢?”- Brian Kernighan - Shepmaster