sag*_*aga 2 type-inference rust type-deduction docopt
使用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());
}
Run Code Online (Sandbox Code Playgroud)
如果你看一下等号右边的表达式,你会发现它没有在Args任何地方提到结构.编译器如何推导出该表达式的返回类型?类型信息可以在Rust中以相反的方向(从初始化目标到初始化表达式)流动吗?
"它是如何工作的?" Stack Overflow可能是一个太大的问题,但(与Scala和Haskell等其他语言一起)Rust的类型系统基于Hindley-Milner类型系统,虽然有许多修改和扩展.
大大简化,其想法是将每个未知类型视为变量,并将类型之间的关系定义为一系列约束,然后可以通过算法求解.在某些方面,它类似于您可能在学校代数中解决的联立方程式.
类型推断是Rust(以及扩展的Hindley-Milner家族中的其他语言)的一个特性,它在惯用代码中被普遍利用:
Rust的类型推断是强大的,正如你所说,可以双向流动.要Vec<T>用作更简单和更熟悉的示例,其中任何一个都是有效的:
let vec = Vec::new(1_i32);
let vec = Vec::<i32>::new();
let vec: Vec<i32> = Vec::new();
Run Code Online (Sandbox Code Playgroud)
甚至可以根据以后如何使用类型来推断类型:
let mut vec = Vec::new();
// later...
vec.push(1_i32);
Run Code Online (Sandbox Code Playgroud)
另一个很好的例子是根据预期的类型选择正确的字符串解析器:
let num: f32 = "100".parse().unwrap();
let num: i128 = "100".parse().unwrap();
let address: SocketAddr = "127.0.0.1:8080".parse().unwrap();
Run Code Online (Sandbox Code Playgroud)
那你原来的例子怎么样?
Docopt::new返回a Result<Docopt, Error>,Result::Err<Error>如果提供的选项无法解析为参数,则返回a .此时,不知道参数是否有效,只是它们是正确形成的.and_then有以下签名:
pub fn and_then<U, F>(self, op: F) -> Result<U, E>
where
F: FnOnce(T) -> Result<U, E>,
Run Code Online (Sandbox Code Playgroud)
变量self具有类型Result<T, E>,其中T是Docopt和E是Error,从步骤1推断U仍是未知数,您提供的关闭后也|d| d.deserialize().T是Docopts,那么deserialize就是Docopts::deserialize,它有签名:
fn deserialize<'a, 'de: 'a, D>(&'a self) -> Result<D, Error>
where
D: Deserialize<'de>
Run Code Online (Sandbox Code Playgroud)
变量self有类型Docopts.D仍然是未知的,但我们知道它U与步骤2中的类型相同.Result::unwrap_or_else 有签名:
fn unwrap_or_else<F>(self, op: F) -> T
where
F: FnOnce(E) -> T
Run Code Online (Sandbox Code Playgroud)
变量self有类型Result<T, Error>.但是,我们知道,T是一样的U,并D从前面的步骤.Args,所以T从上一步开始Args,这意味着D步骤3(和U步骤2)也是如此Args.deserialize,意味着该方法<Args as Deserialize>::deserialize是使用该#[derive(Deserialize)]属性自动派生的.