在此Docopt示例中,类型推导如何工作? [英] How does the type deduction work in this Docopt example?

查看:161
本文介绍了在此Docopt示例中,类型推导如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用docopt库查看以下代码:

Take a look at this code using the docopt library:

const USAGE: &'static str = "...something...";

#[derive(Deserialize)]
struct Args {
    flag: bool,
}

type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;

fn main() {
    let mut args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());
}

如果查看等号右边的表达式,您会发现它在任何地方都没有提及Args结构.编译器如何推断此表达式的返回类型?类型信息是否可以在Rust中以相反的方向(从初始化目标到初始化表达式)流动?

If you look at the expression to the right of equals sign, you'll see that it doesn't mention the Args struct anywhere. How does the compiler deduce the return type of this expression? Can the type information flow in opposite direction (from initialization target to initializer expression) in Rust?

推荐答案

它是如何工作的?" 对于Stack Overflow来说可能是一个太大的问题,但是(以及其他语言,例如Scala和Haskell)Rust的类型系统基于 Hindley-Milner类型系统 ,尽管有许多修改和扩展.

"How does it work?" might be too big of a question for Stack Overflow but (along with other languages like Scala and Haskell) Rust's type system is based on the Hindley-Milner type system, albeit with many modifications and extensions.

极大简化,其思想是将每个未知类型视为变量,并将类型之间的关系定义为一系列约束,然后可以通过算法解决.在某些方面,它类似于您可能在学校的代数中求解的联立方程.

Simplifying greatly, the idea is to treat each unknown type as a variable, and define the relationships between types as a series of constraints, which can then be solved by an algorithm. In some ways it's similar to simultaneous equations you may have solved in algebra at school.

类型推断是Rust(以及扩展的Hindley-Milner系列中的其他语言)的一项功能,该语言已在惯用代码中广泛用于以下用途:

Type inference is a feature of Rust (and other languages in the extended Hindley-Milner family) that is exploited pervasively in idiomatic code to:

  • 减少类型注释的噪音
  • 通过不在多个位置(DRY)硬编码类型来提高可维护性

Rust的类型推断功能强大,正如您所说,可以双向流动.要将Vec<T>用作一个更简单,更熟悉的示例,以下任何一个都是有效的:

Rust's type inference is powerful and, as you say, can flow both ways. To use Vec<T> as a simpler and more familiar example, any of these are valid:

let vec = Vec::new(1_i32);
let vec = Vec::<i32>::new();
let vec: Vec<i32> = Vec::new();

甚至可以根据以后使用类型的方式来推断类型:

The type can even be inferred just based on how a type is later used:

let mut vec = Vec::new();
// later...
vec.push(1_i32);

另一个好的示例是根据预期的类型选择正确的字符串解析器:

Another nice example is picking the correct string parser, based on the expected type:

let num: f32 = "100".parse().unwrap();
let num: i128 = "100".parse().unwrap();
let address: SocketAddr = "127.0.0.1:8080".parse().unwrap();


那么您的原始示例呢?


So what about your original example?

  1. Docopt::new 返回一个Result<Docopt, Error>,如果不能将提供的选项解析为参数,则为Result::Err<Error>.在这一点上,不知道参数是否有效,只是它们的格式正确.
  2. 接下来, and_then 具有以下签名:
  1. Docopt::new returns a Result<Docopt, Error>, which will be Result::Err<Error> if the supplied options can't be parsed as arguments. At this point, there is no knowledge of if the arguments are valid, just that they are correctly formed.
  2. Next, and_then has the following signature:
pub fn and_then<U, F>(self, op: F) -> Result<U, E> 
where
    F: FnOnce(T) -> Result<U, E>,

从步骤1推导出,变量self的类型为Result<T, E>,其中TDocopt,而EError,即使提供了闭包|d| d.deserialize()U仍然是未知的./li>

  • 但是我们知道TDocopts,所以deserialize

    The variable self has type Result<T, E> where T is Docopt and E is Error, deduced from step 1. U is still unknown, even after you supply the closure |d| d.deserialize().

  • But we know that T is Docopts, so deserialize is Docopts::deserialize, which has the signature:

    fn deserialize<'a, 'de: 'a, D>(&'a self) -> Result<D, Error> 
    where
        D: Deserialize<'de>
    

    变量self具有类型Docopts. D仍然未知,但是我们知道它与步骤2中的U相同.

  • Result::unwrap_or_else 具有签名:

    The variable self has type Docopts. D is still unknown, but we know it is the same type as U from step 2.

  • Result::unwrap_or_else has the signature:

    fn unwrap_or_else<F>(self, op: F) -> T 
    where
        F: FnOnce(E) -> T
    

    变量self具有类型Result<T, Error>.但是我们知道T与上一步中的UD相同.

  • 然后我们将变量分配给类型Args,因此上一步中的TArgs,这意味着步骤3中的D(以及步骤2中的U)也为Args.
  • 编译器现在可以推断出,当您编写deserialize时,意味着方法<Args as Deserialize>::deserialize,该方法是使用#[derive(Deserialize)]属性自动派生的.
  • The variable self has type Result<T, Error>. But we know that T is the same as U and D from the previous step.

  • We then assign to a variable of type Args, so T from the previous step is Args, which means that the D in step 3 (and U from step 2) is also Args.
  • The compiler can now deduce that when you wrote deserialize you meant the method <Args as Deserialize>::deserialize, which was derived automatically with the #[derive(Deserialize)] attribute.
  • 这篇关于在此Docopt示例中,类型推导如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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