Rust 如何从 From::<>::from() 推断结果类型? [英] How does Rust infer resultant types from From::<>::from()?

查看:46
本文介绍了Rust 如何从 From::<>::from() 推断结果类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Hyper 示例的这个片段中,我用可以成功编译的类型注释了一些代码:

.map_err(|x: std::io::Error| -> hyper::Error {::std::convert::From::::from(x)})

From::from() 的类型定义好像是 fn from(T) ->自己;

怎么看起来是一个std::io::Error ->Self 似乎返回一个 hyper::Error 值,当我给它的泛型和参数都不属于 hyper::Error 类型时?

即使我明确指定所有类型,似乎也发生了某种隐式类型转换?

解决方案

类型推断有不同程度.

例如,在 C++ 中,每个文字都是类型化的,并且只能实例化完全形成的类型,因此可以计算(并且是)任何表达式的类型.在 C++11 之前,这导致编译器给出错误消息:您正在尝试将 X 类型的值分配给 Y 类型的变量.在 C++11 中,引入了 auto 来让编译器根据分配给它的值确定变量的类型.

在 Java 中,这略有不同:变量的类型必须完全拼写出来,但作为交换,在构造类型时,可以省略通用位,因为它们是从赋值给的变量中推导出来的.

这两个例子很有趣,因为类型信息在它们两个中的流动方式不同,这表明流动没有理由以一种或另一种方式流动;然而,有很多技术限制.

相反,Rust 使用了 Hindley Milner 类型统一算法的变体.

我个人认为 Hindley Milner 是一个等式系统:

  1. 为每个潜在类型命名:A、B、C、...
  2. 根据程序的结构创建将这些类型联系在一起的方程式.

例如,想象以下内容:

fn print_slice(s: &[u32]) {println!("{:?}", s);}fn 主(){让 mut v = Vec::new();v.push(1);print_slice(&v);}

main开始:

  1. 为类型分配名称:v =>A, 1 =>B,
  2. 提出一些等式:A = Vec(来自v = Vec::new()),C = B(来自 v.push(1)),A = &[u32] OR ::Output = &[u32] OR ...(来自 print_slice(&v),
  3. 第一轮求解:A = Vec, &[B] = &[u32],
  4. 第二轮求解:B = u32A = Vec.

由于子类型(原始 HM 没有),因此在混合中存在一些困难,但本质上就是这样.

在这个过程中,没有考虑后退或前进,只是求解方程.

这个过程被称为类型统一,如果它失败,你会得到一个很有帮助的编译器错误.

In this snippet from Hyper's example, there's a bit of code that I've annotated with types that compiles successfully:

.map_err(|x: std::io::Error| -> hyper::Error {
    ::std::convert::From::<std::io::Error>::from(x)
})

The type definition of From::from() seems to be fn from(T) -> Self;

How is it that what seems to be a std::io::Error -> Self seems to return a hyper::Error value, when none of the generics and arguments I give it are of the type hyper::Error?

It seems that some sort of implicit type conversion is happening even when I specify all the types explicitly?

解决方案

Type inference has varying degrees.

For example, in C++ each literal is typed, and only a fully formed type can be instantiated, therefore the type of any expression can be computed (and is). Before C++11, this led to the compiler giving an error message: You are attempting to assign a value of type X to a variable of type Y. In C++11, auto was introduced to let the compiler figure out the type of the variable based on the value that was assigned to it.

In Java, this works slightly differently: the type of a variable has to be fully spelled out, but in exchange when constructing a type the generic bits can be left out since they are deduced from the variable the value is assigned to.

Those two examples are interesting because type information does not flow the same way in both of them, which hints that there is no reason for the flow to go one way or another; there are however technical constraints aplenty.

Rust, instead, uses a variation of the Hindley Milner type unification algorithm.

I personally see Hindley Milner as a system of equation:

  1. Give each potential type a name: A, B, C, ...
  2. Create equations tying together those types based on the structure of the program.

For example, imagine the following:

fn print_slice(s: &[u32]) {
    println!("{:?}", s);
}

fn main() {
    let mut v = Vec::new();
    v.push(1);
    print_slice(&v);
}

And start from main:

  1. Assign names to types: v => A, 1 => B,
  2. Put forth some equations: A = Vec<C> (from v = Vec::new()), C = B (from v.push(1)), A = &[u32] OR <A as Deref>::Output = &[u32] OR ... (from print_slice(&v),
  3. First round of solving: A = Vec<B>, &[B] = &[u32],
  4. Second round of solving: B = u32, A = Vec<u32>.

There are some difficulties woven into the mix because of subtyping (which the original HM doesn't have), however it's essentially just that.

In this process, there is no consideration for going backward or forwarded, it's just equation solving either way.

This process is known as Type Unification and if it fails you get a hopefully helpful compiler error.

这篇关于Rust 如何从 From::&lt;&gt;::from() 推断结果类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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