如何从文件或 URL 创建 Rust Quick XML 阅读器?

kla*_*usi 5 rust

我有使用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)))
}
Run Code Online (Sandbox Code Playgroud)

返回类型是动态的:具有来自文件或响应正文的数据的 Reader。

编译错误:

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`
Run Code Online (Sandbox Code Playgroud)

编译器认为我们总是想从文件中读取,但这里是一个响应流。如何告诉编译器接受 XML 读取器中的两种类型的缓冲读取器?

edw*_*rdw 4

返回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)))
    }
}
Run Code Online (Sandbox Code Playgroud)

附带说明一下,混合本地路径和远程 URL 并不是一个好主意。仅仅local_path.is_file()不足以净化输入。你已被警告过。