我有以下代码使用 quick_xml 库:
use quick_xml::Reader;
use std::io::BufRead;
use std::path::Path;
use std::io::BufReader;
/// Returns an XML stream either from a file or a URL.
fn get_xml_stream(source: &str) -> Result<Reader<impl BufRead>, Error> {
let local_path = Path::new(source);
// Try to read a local file first.
if local_path.is_file() {
let reader =
Reader::from_file(source).context(format!("couldn't read file {:?}", source))?;
return Ok(reader);
}
// Try to fetch a remote file.
let response = reqwest::get(source).context(format!(
"File not found and failed fetching from remote URL {}",
source
))?;
if !response.status().is_success() {
return Err(format_err!("XML download failed with {:#?}", response));
}
Ok(Reader::from_reader(BufReader::new(response)))
}
返回类型是动态的:具有来自文件或响应正文的数据的读取器。
编译错误:
error[E0308]: mismatched types
--> src/main.rs:225:43
|
225 | Ok(Reader::from_reader(BufReader::new(response)))
| ^^^^^^^^ expected struct `std::fs::File`, found struct `reqwest::response::Response`
|
= note: expected type `std::fs::File`
found type `reqwest::response::Response`
编译器认为我们总是想从文件中读取,但这是一个响应流。如何告诉编译器在 XML 读取器中接受这两种类型的缓冲读取器?
返回impl SomeTrait
意味着该函数返回一个实现该特征的具体类型,而您只是不想拼写出它是什么类型。这并不意味着它可以返回异类类型。
Box<dyn BufRead>
在这里是正确的选择:
use failure::{Error, format_err, ResultExt}; // failure = "0.1.6"
use quick_xml::Reader; // quick-xml = "0.17.2"
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
/// Returns an XML stream either from a file or a URL.
fn get_xml_stream(source: &str) -> Result<Reader<Box<dyn BufRead>>, Error> {
let local_path = Path::new(source);
if local_path.is_file() {
let file = File::open(local_path)?;
let reader = BufReader::new(file);
Ok(Reader::from_reader(Box::new(reader)))
} else {
let response = reqwest::get(source).context(format!(
"File not found and failed fetching from remote URL {}",
source
))?;
if !response.status().is_success() {
return Err(format_err!("XML download failed with {:#?}", response));
}
let reader = BufReader::new(response);
Ok(Reader::from_reader(Box::new(reader)))
}
}
作为旁注,混合本地路径和远程 URL 不是一个好主意。仅仅local_path.is_file()
不足以净化输入。你已经被警告了。