使用docopt库查看以下代码:
{
"data" : [
{"key":"val","key":"val"},
{"key":"val","key":"val"},
{"key":"val","key":"val"},
{"id":"666","name":"jnit"}
]
}
如果查看等号右边的表达式,您会发现它在任何地方都没有提到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());
}
结构。编译器如何推断此表达式的返回类型?类型信息能否在Rust中以相反的方向(从初始化目标到初始化表达式)流动?
答案 0 :(得分:5)
“它是如何工作的?” 对于Stack Overflow来说可能是一个太大的问题,但是(以及其他语言,例如Scala和Haskell)Rust的类型系统基于the Hindley-Milner type system,尽管有许多修改和扩展。
极大简化,其思想是将每个未知类型视为变量,并将类型之间的关系定义为一系列约束,然后可以通过算法解决。在某些方面,它类似于您可能在学校的代数中求解的联立方程。
类型推断是Rust(以及扩展的Hindley-Milner系列中的其他语言)的一项功能,该语言已在惯用代码中广泛用于以下用途:
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();
那么您的原始示例呢?
Docopt::new
返回一个Result<Docopt, Error>
,如果不能将提供的选项解析为参数,则返回Result::Err<Error>
。在这一点上,不知道参数是否有效,只是它们的格式正确。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>
,其中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>
变量self
的类型为Docopts
。 D
仍然未知,但我们知道它与步骤2中的U
相同。Result::unwrap_or_else
具有签名:
fn unwrap_or_else<F>(self, op: F) -> T
where
F: FnOnce(E) -> T
变量self
的类型为Result<T, Error>
。但是我们知道T
与上一步中的U
和D
相同。Args
的变量,因此上一步中的T
是Args
,这意味着步骤3中的D
(和{{步骤2)中的1}}也是U
。Args
时,意味着方法deserialize
是通过<Args as Deserialize>::deserialize
属性自动派生的。