gpt4 book ai didi

rust - 类型推导在这个 Docopt 示例中是如何工作的?

转载 作者:行者123 更新时间:2023-11-29 08:02:44 24 4
gpt4 key购买 nike

使用 docopt 库查看这段代码:

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 中,类型信息可以反向流动(从初始化目标到初始化表达式)吗?

最佳答案

“它是如何工作的?” 对于 Stack Overflow 来说可能是一个太大的问题,但是(连同其他语言如 Scala 和 Haskell)Rust 的类型系统是基于 the Hindley-Milner type system 的。 ,尽管有许多修改和扩展。

大大简化,思路是把每一个未知的类型都当作一个变量,把类型之间的关系定义为一系列的约束条件,然后通过算法来求解。在某些方面,它类似于您在学校用代数求解的联立方程。


类型推断 是 Rust(以及扩展的 Hindley-Milner 家族中的其他语言)的一个特性,在惯用代码中被普遍利用以:

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

Rust 的类型推断非常强大,正如您所说,可以双向流动。使用 Vec<T>作为一个更简单和更熟悉的示例,以下任何一个都是有效的:

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

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

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

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

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

那么你原来的例子呢?

  1. Docopt::new 返回 Result<Docopt, Error> ,这将是 Result::Err<Error>如果提供的选项不能被解析为参数。此时,不知道参数是否有效,只知道它们的格式是否正确。
  2. 接下来, and_then 具有以下签名:
    pub fn and_then<U, F>(self, op: F) -> Result<U, E> 
    where
    F: FnOnce(T) -> Result<U, E>,
    变量 self类型为 Result<T, E>其中 TDocoptEError ,从步骤 1 推导出来。U仍然未知,即使在您提供闭包之后也是如此|d| d.deserialize() .
  3. 但我们知道TDocopts , 所以 deserialize Docopts::deserialize ,其签名为:
    fn deserialize<'a, 'de: 'a, D>(&'a self) -> Result<D, Error> 
    where
    D: Deserialize<'de>
    变量 self类型为 Docopts . D仍然未知,但我们知道它与 U 属于同一类型从第 2 步开始。
  4. Result::unwrap_or_else 有签名:
    fn unwrap_or_else<F>(self, op: F) -> T 
    where
    F: FnOnce(E) -> T
    变量 self类型为 Result<T, Error> .但我们知道TU相同和 D来自上一步。
  5. 然后我们分配给类型为Args的变量, 所以 T来自上一步的是Args ,这意味着 D在第 3 步中(和第 2 步中的 U)也是 Args .
  6. 编译器现在可以推断出你写的是deserialize。你的意思是方法<Args as Deserialize>::deserialize ,它是用 #[derive(Deserialize)] 自动派生的属性。

关于rust - 类型推导在这个 Docopt 示例中是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54884862/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com