如何获得 return 类似字符串的 Vec 的函数?
How do I get a function to return a Vec of string-like things?
我有一大段代码可以打开文件并逐行搜索内容,然后对每个匹配行执行一些操作。我想将其分解到它自己的函数中,该函数采用文件路径并为您提供匹配的行,但我不知道如何正确分解它。
这是我认为接近的结果,但我收到编译器错误:
/// get matching lines from a path
fn matching_lines(p: PathBuf, pattern: &Regex) -> Vec<String> {
let mut buffer = String::new();
// TODO: maybe move this side effect out, hand it a
// stream of lines or otherwise opened file
let mut f = File::open(&p).unwrap();
match f.read_to_string(&mut buffer) {
Ok(yay_read) => yay_read,
Err(_) => 0,
};
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| pattern.is_match(x)).collect();
return m_lines;
}
编译错误:
src/main.rs:109:43: 109:52 error: the trait `core::iter::FromIterator<&str>` is not implemented for the type `collections::vec::Vec<collections::string::String>` [E0277]
src/main.rs:109 .filter(|&x| pattern.is_match(x)).collect();
^~~~~~~~~
src/main.rs:109:43: 109:52 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:109:43: 109:52 note: a collection of type `collections::vec::Vec<collections::string::String>` cannot be built from an iterator over elements of type `&str`
src/main.rs:109 .filter(|&x| pattern.is_match(x)).collect();
^~~~~~~~~
error: aborting due to previous error
如果我使用 String
而不是 &str
,则会收到此错误:
src/main.rs:108:30: 108:36 error: `buffer` does not live long enough
src/main.rs:108 let m_lines: Vec<&str> = buffer.lines()
^~~~~~
哪种说得通。我猜这些行留在 buffer
内,它在函数末尾超出范围,因此收集对字符串的引用向量并不能真正帮助我们。
我如何return行的集合?
您可以使用 map
函数将字符串切片转换为拥有的 String
对象。
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| pattern.is_match(x))
.map(|x| x.to_owned())
.collect();
然后您应该可以从函数中 return m_lines
。
让我们从这个版本开始,它在提问时运行在Rust Playground (it's a good idea to make a MCVE上:
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
fn matching_lines(p: PathBuf, pattern: &str) -> Vec<String> {
let mut buffer = String::new();
let mut f = File::open(&p).unwrap();
match f.read_to_string(&mut buffer) {
Ok(yay_read) => yay_read,
Err(_) => 0,
};
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| x.contains(pattern)).collect();
return m_lines;
}
fn main() {
let path = PathBuf::from("/etc/hosts");
let lines = matching_lines(path, "local");
}
让我们看看str::lines
的签名:
fn lines(&self) -> Lines // with lifetime elision
fn lines<'a>(&'a self) -> Lines<'a> // without
我首先展示了它在源代码中的样子,然后你可以在脑海中将其翻译成什么。它将 return 一个由您已阅读的 String
支持的字符串切片的迭代器。这是一件好事,因为它非常有效,因为只需要进行一次分配。但是,您不能 . The easiest thing to do is convert each of the lines into an owned string, as 建议:
let m_lines: Vec<String> =
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect();
这让您的代码可以编译,但它仍然可以做得更好。您的 match
语句可以替换为 unwrap_or
,但由于您完全忽略了错误情况,您最好使用 _
:
let _ = f.read_to_string(&mut buffer);
请注意,这确实不是一个好主意。报告错误很重要,当你最需要报告错误时,扔掉错误会咬你一口!使用 unwrap
并在发生错误时让您的程序终止可能更安全。
其次,除非需要,否则不要使用显式 return
语句并且不要提供类型注释。由于您的函数 return 是 Vec<String>
,您可以将最后两行替换为:
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect()
您还可以更开放地了解您为 p
接受的类型,以更好地匹配 File::open
支持的类型:
fn matching_lines<P>(p: P, pattern: &str) -> Vec<String>
where P: AsRef<Path>
总计:
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Read;
fn matching_lines<P>(p: P, pattern: &str) -> Vec<String>
where P: AsRef<Path>
{
let mut buffer = String::new();
let mut f = File::open(p).unwrap();
let _ = f.read_to_string(&mut buffer);
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect()
}
fn main() {
let path = PathBuf::from("/etc/hosts");
let lines = matching_lines(path, "local");
println!("{:?}", lines);
}
我有一大段代码可以打开文件并逐行搜索内容,然后对每个匹配行执行一些操作。我想将其分解到它自己的函数中,该函数采用文件路径并为您提供匹配的行,但我不知道如何正确分解它。
这是我认为接近的结果,但我收到编译器错误:
/// get matching lines from a path
fn matching_lines(p: PathBuf, pattern: &Regex) -> Vec<String> {
let mut buffer = String::new();
// TODO: maybe move this side effect out, hand it a
// stream of lines or otherwise opened file
let mut f = File::open(&p).unwrap();
match f.read_to_string(&mut buffer) {
Ok(yay_read) => yay_read,
Err(_) => 0,
};
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| pattern.is_match(x)).collect();
return m_lines;
}
编译错误:
src/main.rs:109:43: 109:52 error: the trait `core::iter::FromIterator<&str>` is not implemented for the type `collections::vec::Vec<collections::string::String>` [E0277]
src/main.rs:109 .filter(|&x| pattern.is_match(x)).collect();
^~~~~~~~~
src/main.rs:109:43: 109:52 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:109:43: 109:52 note: a collection of type `collections::vec::Vec<collections::string::String>` cannot be built from an iterator over elements of type `&str`
src/main.rs:109 .filter(|&x| pattern.is_match(x)).collect();
^~~~~~~~~
error: aborting due to previous error
如果我使用 String
而不是 &str
,则会收到此错误:
src/main.rs:108:30: 108:36 error: `buffer` does not live long enough
src/main.rs:108 let m_lines: Vec<&str> = buffer.lines()
^~~~~~
哪种说得通。我猜这些行留在 buffer
内,它在函数末尾超出范围,因此收集对字符串的引用向量并不能真正帮助我们。
我如何return行的集合?
您可以使用 map
函数将字符串切片转换为拥有的 String
对象。
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| pattern.is_match(x))
.map(|x| x.to_owned())
.collect();
然后您应该可以从函数中 return m_lines
。
让我们从这个版本开始,它在提问时运行在Rust Playground (it's a good idea to make a MCVE上:
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
fn matching_lines(p: PathBuf, pattern: &str) -> Vec<String> {
let mut buffer = String::new();
let mut f = File::open(&p).unwrap();
match f.read_to_string(&mut buffer) {
Ok(yay_read) => yay_read,
Err(_) => 0,
};
let m_lines: Vec<String> = buffer.lines()
.filter(|&x| x.contains(pattern)).collect();
return m_lines;
}
fn main() {
let path = PathBuf::from("/etc/hosts");
let lines = matching_lines(path, "local");
}
让我们看看str::lines
的签名:
fn lines(&self) -> Lines // with lifetime elision
fn lines<'a>(&'a self) -> Lines<'a> // without
我首先展示了它在源代码中的样子,然后你可以在脑海中将其翻译成什么。它将 return 一个由您已阅读的 String
支持的字符串切片的迭代器。这是一件好事,因为它非常有效,因为只需要进行一次分配。但是,您不能
let m_lines: Vec<String> =
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect();
这让您的代码可以编译,但它仍然可以做得更好。您的 match
语句可以替换为 unwrap_or
,但由于您完全忽略了错误情况,您最好使用 _
:
let _ = f.read_to_string(&mut buffer);
请注意,这确实不是一个好主意。报告错误很重要,当你最需要报告错误时,扔掉错误会咬你一口!使用 unwrap
并在发生错误时让您的程序终止可能更安全。
其次,除非需要,否则不要使用显式 return
语句并且不要提供类型注释。由于您的函数 return 是 Vec<String>
,您可以将最后两行替换为:
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect()
您还可以更开放地了解您为 p
接受的类型,以更好地匹配 File::open
支持的类型:
fn matching_lines<P>(p: P, pattern: &str) -> Vec<String>
where P: AsRef<Path>
总计:
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Read;
fn matching_lines<P>(p: P, pattern: &str) -> Vec<String>
where P: AsRef<Path>
{
let mut buffer = String::new();
let mut f = File::open(p).unwrap();
let _ = f.read_to_string(&mut buffer);
buffer
.lines()
.filter(|&x| x.contains(pattern))
.map(ToOwned::to_owned)
.collect()
}
fn main() {
let path = PathBuf::from("/etc/hosts");
let lines = matching_lines(path, "local");
println!("{:?}", lines);
}