结果得到意外的类型参数

C.N*_*ivs 6 rust

我试图从文件中读取值以创建一个结构体,但我遇到了一对奇怪的错误。我的代码的超级基本实现:

extern crate itertools;

use itertools::Itertools;
use std::io::{self, prelude::*, BufReader};
use std::fs::{self, File};

// The struct I will unpack into
struct BasicExample {
    a: String,
    b: String,
    c: String,
    d: String,
}

impl BasicExample {
    pub fn new(a: String, b: String, c: String, d: String} -> Self {
        BasicExample {
            a, b, c, d
        }
    }

    // I'm expecting that reading from the config file might fail, so
    // I want to return a Result that can be unwrapped. Otherwise an Err
    // will be returned with contained value being &'static str
    pub fn from_config(filename: &str) -> io::Result<Self, &'static str> {
        let file = File::open(filename).expect("Could not open file");

        // read args into a Vec<String>, consuming file
        let args: Vec<String> = read_config(file);

        // I transfer ownership away from args here
        let params: Option<(String, String, String, String)> = args.drain(0..4).tuples().next();

        // Then I want to match and return, I could probably do if-let here
        // but I don't have my hands around the base concept yet, so I'll 
        // leave that for later
        match params {
            Some((a, b, c, d)) => Ok(BasicExample::new(a, b, c, d)),
            _ => Err("Could not read values into struct")
        }
    }

    fn read_config(file: File) -> Vec<String> {
        let buf = BufReader::new(file);

        buf.lines()
            .map(|l| l.expect("Could not parse line"))
            .collect()
    }
}
Run Code Online (Sandbox Code Playgroud)

运行cargo check以确保我没有错过任何东西,我收到以下错误:

error[E0107]: wrong number of type arguments: expected 1, found 2
  --> src/lib.rs:37:60
   |
37 |     pub fn from_config(filename: &str) -> io::Result<Self, &'static str> {
   |                                                            ^^^^^^^^^^^^ unexpected type argument

error: aborting due to previous error

For more information about this error, try `rustc --explain E0107`.
Run Code Online (Sandbox Code Playgroud)

好像有点奇怪。io::Resultshould take <T, E>,我已经给了它E,所以让我们删除那个类型参数,看看会发生什么:

error[E0308]: mismatched types
  --> src/lib.rs:54:22
   |
54 |             _ => Err("Could not read values into AzureAuthentication struct"),
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::io::Error`, found reference
   |
   = note: expected type `std::io::Error`
              found type `&'static str`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
Run Code Online (Sandbox Code Playgroud)

出于某种原因,它真的对E我提供的不满意。我是一个完全的 Rust 初学者,所以也许我只是不确定我在看什么。我在这里做错了什么?该itertools所有权诀窍是借来的(公顷)从这个精彩的回答

系统详情:

  • macOS 10.13.6
  • rustc 1.36.0 (a53f9df32 2019-07-03)
  • 货物 1.36.0 (c4fcfb725 2019-05-15)

Séb*_*uld 9

这实际上是一个超级基本的错误,但在您了解(和爱)之前,它看起来很神秘std::io

简而言之,std::result::Result(你知道的结果) !== std::io::Result。第一个文档在这里,第二个在这里

您会在第二个中注意到它实际上是Result<T, std::io::Error>. 这意味着它实际上是它的简写,其中您的错误案例是std::io::Error.

因此,当您尝试Err()使用字符串切片时,您的代码是不正确的(因为切片std::io::Error显然不是)。

有多种方法可以解决此问题:

  • 您可以将整个错误链转换为另一种类型(显式或利用into()强制转换)
  • 您可以使自己的错误返回std::io::Error实例

这两个选项都有有效的情况,这就是我提到两者的原因。第二个相对容易完成,就像这样(完整路径用于文档目的)。假设您返回一个与未找到实体匹配的错误。你可以这样做:

`Err(std::io::Error::new(std::io::ErrorKind::NotFound, "Could not read values into AzureAuthentication struct"))`
Run Code Online (Sandbox Code Playgroud)

但是,对于您的功能,有一种更好的方法:

pub fn from_config(filename: &str) -> io::Result<Self> {
    let file = File::open(filename)?;
    let args: Vec<String> = read_config(file); // This has no error possibility

    let params: Option<(String, String, String, String)> = args.drain(0..4).tuples().next();
    params.ok_or(std::io::Error::new(std::io::ErrorKind::NotFound, "Could not read values into struct")).map(|(a, b, c, d)| BasicExample::new(a,b,c,d))
}
Run Code Online (Sandbox Code Playgroud)

这会从您的方法中删除所有间接性,并整齐地将错误类型一一折叠起来,因此您不必担心它们。在Option被变成了Result感谢ok_or,一切都很好在世界上最好的:-)


tur*_*too 7

Rust 中的一个常见模式是,如果您的模块使用了很多Result<T, ModuleSpecificErrorType>,那么您可以进行自定义Result<T>以抽象出错误类型。此自定义类型少了一个通用参数,因为错误类型是硬编码的。

Astd::io::Result<T>是对 的抽象std::result:Result<T, std::io::Error>

请参阅的文档io::Result