Rust如何从From ::<> :: from()推断出结果类型?

时间:2017-06-24 13:57:55

标签: rust

在Hyper的示例中,有一些代码可以用成功编译的类型进行注释:

driver.find_element_by_xpath("//td[@class=​'CreateQuoteBigButtonCell3‌' and @id=​'pt1:r1:0:cf16cl‌']").click()

.map_err(|x: std::io::Error| -> hyper::Error { ::std::convert::From::<std::io::Error>::from(x) }) 的类型定义似乎是From::from()

当我给出的任何泛型和参数都不是fn from(T) -> Self;类型时,看起来似乎std::io::Error -> Self似乎返回hyper::Error值是怎么回事?

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

2 个答案:

答案 0 :(得分:6)

Rust中的类型信息可以向后流动。

闭包的返回类型指定为hyper::Error。因此,块的结果必须为hyper::Error,因此From::from的结果必须为hyper::Error

如果您愿意,可以使用......

<hyper::Error as ::std::convert::From>::<std::io::Error>::from(x)

......这将是更完全合格的版本。但是在那里有闭包返回类型,这是不必要的。

答案 1 :(得分:3)

类型推断有不同程度。

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

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

这两个例子很有意思,因为类型信息在两者中都不会以相同的方式流动,这暗示了流程没有理由以这种或那种方式流动;但是有很多技术限制。

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

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

  1. 为每个潜在类型命名:A,B,C,......
  2. 根据程序结构创建将这些类型捆绑在一起的方程式。
  3. 例如,想象一下:

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

    main开始:

    1. 为类型指定名称:v => A1 => B
    2. 提出一些方程:A = Vec<C>(来自v = Vec::new()),C = B(来自v.push(1)),A = &[u32]<A as Deref>::Output = &[u32]或{{ 1}}(来自...
    3. 第一轮解决:print_slice(&v)A = Vec<B>
    4. 第二轮解决:&[B] = &[u32]B = u32
    5. 由于子类型(原来的HM没有),混合编织有一些困难,但它基本上就是这样。

      在这个过程中,没有考虑后退或转发,它只是解决方程式。

      此过程称为类型统一,如果失败,则会出现希望有用的编译器错误。