为什么要连接我的迭代器中的字符串?
Why are the strings in my iterator being concatenated?
我最初的目标是获取一个单词列表,每行一个,并将它们放在 HashSet
中,同时丢弃注释行并正确引发 I/O 错误。给定文件 "stopwords.txt":
a
# this is actually a comment
of
the
this
我设法使代码编译成这样:
fn stopword_set() -> io::Result<HashSet<String>> {
let words = Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}));
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 4);
}
这里有一个 playground 也创建了上面的文件。
我希望在程序结束时有一组 4 个字符串。令我惊讶的是,该函数实际上 returns 一个包含单个字符串的集合,所有单词都连接在一起:
{"aofthethis"}
thread 'main' panicked at 'assertion failed: `(left == right)` (left: `1`, right: `4`)'
根据 FromIterator
, I got rid of all calls to from_iter
and used collect
instead (Playground) 的文档中的一条建议,确实解决了问题。
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}).collect()
}
为什么之前对 from_iter
的调用导致了意外的推论,而 collect()
却按预期工作?
更简单的复制:
use std::collections::HashSet;
use std::iter::FromIterator;
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
let words = Result::from_iter(input.into_iter());
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 2);
}
问题是在这里,我们从迭代器中收集了两次。 words
的类型是 Result<_, u8>
。但是,Result
也 实现了 Iterator
本身,所以当我们最后调用 from_iter
时,编译器会看到 Ok
类型必须是 String
由于方法签名。向后工作,您可以从 Strings
的迭代器构造一个 String
,这就是编译器选择的内容。
删除第二个 from_iter
即可解决:
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
Result::from_iter(input.into_iter())
}
或者你的原创:
fn stopword_set() -> io::Result<HashSet<String>> {
Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}))
}
当然,我通常建议改用 collect
,因为我更喜欢链接:
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true,
})
.collect()
}
我最初的目标是获取一个单词列表,每行一个,并将它们放在 HashSet
中,同时丢弃注释行并正确引发 I/O 错误。给定文件 "stopwords.txt":
a
# this is actually a comment
of
the
this
我设法使代码编译成这样:
fn stopword_set() -> io::Result<HashSet<String>> {
let words = Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}));
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 4);
}
这里有一个 playground 也创建了上面的文件。
我希望在程序结束时有一组 4 个字符串。令我惊讶的是,该函数实际上 returns 一个包含单个字符串的集合,所有单词都连接在一起:
{"aofthethis"}
thread 'main' panicked at 'assertion failed: `(left == right)` (left: `1`, right: `4`)'
根据 FromIterator
, I got rid of all calls to from_iter
and used collect
instead (Playground) 的文档中的一条建议,确实解决了问题。
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}).collect()
}
为什么之前对 from_iter
的调用导致了意外的推论,而 collect()
却按预期工作?
更简单的复制:
use std::collections::HashSet;
use std::iter::FromIterator;
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
let words = Result::from_iter(input.into_iter());
Ok(HashSet::from_iter(words))
}
fn main() {
let set = stopword_set().unwrap();
println!("{:?}", set);
assert_eq!(set.len(), 2);
}
问题是在这里,我们从迭代器中收集了两次。 words
的类型是 Result<_, u8>
。但是,Result
也 实现了 Iterator
本身,所以当我们最后调用 from_iter
时,编译器会看到 Ok
类型必须是 String
由于方法签名。向后工作,您可以从 Strings
的迭代器构造一个 String
,这就是编译器选择的内容。
删除第二个 from_iter
即可解决:
fn stopword_set() -> Result<HashSet<String>, u8> {
let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())];
Result::from_iter(input.into_iter())
}
或者你的原创:
fn stopword_set() -> io::Result<HashSet<String>> {
Result::from_iter(
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true
}))
}
当然,我通常建议改用 collect
,因为我更喜欢链接:
fn stopword_set() -> io::Result<HashSet<String>> {
BufReader::new(File::open("stopwords.txt")?)
.lines()
.filter(|r| match r {
&Ok(ref l) => !l.starts_with('#'),
_ => true,
})
.collect()
}