< 返回版块

nightycd 发表于 2020-09-25 18:34

最近在看hyper的源码,对于其实例中的这一句很不能理解 Ok::<_, Infallible>(service_fn(hello_world))

想请问一下,这Ok::<_, Infallible>(...)是个什么语法?具体代表什么含义?

评论区

写评论
作者 nightycd 2020-10-15 11:30

OK,感谢各位的详细解释,我想我大概明白了

solarsail 2020-09-26 10:58

首先,如 @cy2081 所说,一个 Ok 变量实际上是 Result<T, E>::Ok(T)。其中 T 代表成功状态下返回的值的类型,E 是失败时返回的错误对象的类型。之所以需要写成贴主所说的这种形式,应该是这个变量在使用处没有足够的信息能够推导出 Result<T, E>E 的类型,所以需要手动加上。比如单纯一句 let r = Ok(0u32),那么编译器只能知道 r: Result<u32, ???>,而对应的 E 是无从得知的。但是平常这么写没出现什么问题,是因为有其他的条件在限制,比如(最简单的例子)一个函数是 fn f() -> Result<u32, String>,那么在里面写 { let r = Ok(0u32); r } 就是没问题的,因为编译器会从返回值类型推导出 r 的正确类型。

其次,贴主的这种情况经常出现在函数可以接受任意类型参数,而调用方需要传入 Result 作为参数的时候,由于自由度太大无法确定 Result 中模板参数的实际类型。我见过的一个例子是通过 channel 传 Result,比如 std::sync::mpsc::Sender::send,因为接受的参数类型 T 一般只需要 Send,没有其他约束,所以要传 Ok 的话必须标明 E 的类型。

至于针对 struct BBB<F,R,C>,使用 Result 的类型会是 Result<BBB<F,R,C>, E>,也就是将 BBB<F,R,C> 作为 T。如果要在一些无法推导的场合使用,会是类似这种 let bbb = BBB::new(...); let r = Ok::<_, &str>(bbb); let e = Err::<BBB<F,R,C>, _>("failed")。前者能从 bbb 得知 TBBB<F,R,C>,但 E 不清楚,需要标注;后者 E 是能直接推导出来(即"failed"的类型 &str),而 T 需要手动说明。

最后,Infallible 类型是一种无法实例化的类型,也就是在说这里永远不可能出现 Err 的情况。

cy2081 2020-09-25 22:34

我的理解是,Ok是一种Result枚举(enum)值,其中包裹的具体值是service_fn(hello_world),下划线 _ 表示占位符,相当于泛型Result<T, E>定义中的T,表示不在乎T的具体类型是什么,Infallible相当于E,也就是有错误时的类型。对于struct BBB,一般需要先有个new函数生成实例,比如:let new_bbb = BBB::new(), 如果要在Ok中包裹new_bbb, 比如可以表示成 OK::<BBB, err>(new_bbb),err是自己指定的错误的类型。

作者 nightycd 2020-09-25 19:36

意思是不是因为service_fn返回的是个带泛型的结构体ServiceFn<F, R>,所以要给Ok(T)指定T的类型为一个带泛型的值,所以写成Ok::<_,Infallible>(service_fn())的形式对吧,那是不是说比如我定义一个struct BBB<F,R,C>,然后需要用Ok包裹这个BBB结构的话,得写成 Ok::<F,R,C>(BBB)得形式,不知道这样理解对不对。

Cupnfish 2020-09-25 19:13

https://matematikaadit.github.io/posts/rust-turbofish.html

Cupnfish 2020-09-25 19:12

https://turbo.fish/

这个是指定泛型的时候用的。

作者 nightycd 2020-09-25 18:50

是说返回的是个Ok(T)的值,T的类型是<_,Infallible>吗???

1 共 7 条评论, 1 页