结果得到意外的类型参数 [英] Result getting unexpected type argument

查看:38
本文介绍了结果得到意外的类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am attempting to read values from a file in order to create a struct, and I'm getting a weird pair of errors. A super basic implementation of my code:

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()
    }
}

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

Running cargo check to make sure I didn't miss anything, I get the following error:

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`.

看起来有点奇怪.io::Result 应该取 <T, E>,而且我已经给了它 E,所以让我们移除那个类型参数并看看会发生什么:

Seems a bit odd. io::Result should take <T, E>, and I've given it E, so let's remove that type argument and see what happens:

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`.

出于某种原因,它对我提供的 E 真的不满意.我是一个完全的 Rust 初学者,所以也许我只是不确定我在看什么.我在这里做错了什么?itertools 所有权技巧是从 这个精彩答案 中借用 (ha) 的.

For some reason it is really not happy with the E I provided. I'm a complete beginner with rust, so maybe I'm just not sure what I'm looking at. What am I doing wrong here? The itertools ownership trick was borrowed (ha) from this wonderful answer.

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

推荐答案

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

This is actually a super basic error, but one that looks arcane until you get to know (and love) std::io.

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

In short, std::result::Result (the result you know) !== std::io::Result. The documentation for the first is here, while the second is here

您会在第二个中注意到它实际上是 Result 的类型别名.这意味着它是它的有效简写,其中您的错误案例是 std::io::Error 的一个实例.

You'll notice on the second one that it is actually a type alias to Result<T, std::io::Error>. What this means is that it is effectively shorthand for that, where your error case is an instance of std::io::Error.

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

As a result, your code is incorrect when you are attempting to just Err() it with a string slice (since the slice is not std::io::Error, evidently).

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

There are multiple ways to fix this:

  • 您可以将整个错误链转换为另一种类型(显式或利用 into() 强制转换)
  • 您可以让自己的错误返回 std::io::Error 实例
  • You can convert your entire error chain to another type (explicitly or by taking advantage of into() casts)
  • You can make your own errors return std::io::Error instances

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

There are valid cases for both options, which is why I'm mentioning both. The second is done relatively easily, like so (full paths are there for documentation purposes). Suppose you're returning an error which matches an entity not found. You would be able to do it like so:

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

但是,对于您的函数,有更好的方法:

There is, however, a better way for your function:

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))
}

这会从您的方法中删除所有间接性,并整齐地将错误类型一一折叠起来,因此您不必担心它们.由于 ok_orOption 变成了 Result,并且一切都很好:-)

This removes all the indirection from your method and neatly folds away the error types, one by one, so you don't have to worry about them. The Option gets turned into a Result thanks to ok_or, and all is well in the best of worlds :-)

这篇关于结果得到意外的类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆