假设我想对引用实现转换。在本例中,它是从 的转换&f64 -> Foo。
use std::convert::{TryFrom, TryInto};
struct Foo {
a: f64
}
impl TryFrom<&f64> for Foo {
type Error = String;
fn try_from(value: &f64) -> Result<Foo, String> {
Ok(Foo {
a: *value
})
}
}
fn main(){
let foo: Foo = 5.0.try_into().unwrap();
let bar: Foo = (&5.0).try_into().unwrap();
}
Run Code Online (Sandbox Code Playgroud)
(是的,当然这是一个毫无意义和愚蠢的例子,但它有助于简化问题)
现在,主方法中的第二行通过手动借用成功了。但是,如果没有手动借用,主方法中的第一行就会失败并出现以下错误:
error[E0277]: the trait bound `Foo: From<{float}>` is not satisfied
--> src/main.rs:18:24
|
18 | let foo: Foo = 5.0.try_into().unwrap();
| ^^^^^^^^ the trait `From<{float}>` is not implemented for `Foo`
|
= note: required because of the requirements on the impl of `Into<Foo>` for `{float}`
note: required because of the requirements on the impl of `TryFrom<{float}>` for `Foo`
--> src/main.rs:7:6
|
7 | impl TryFrom<&f64> for Foo {
| ^^^^^^^^^^^^^ ^^^
= note: required because of the requirements on the impl of `TryInto<Foo>` for `{float}`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
Run Code Online (Sandbox Code Playgroud)
为什么自动借阅在这里不起作用?
正如错误消息所暗示的那样,问题是the trait bound Foo: From<{float}> is not satisfied。当匹配特征时,Rust不会执行任何强制,而是探测合适的方法。这实际上记录在The Rustonomicon中,读到
请注意,我们在匹配特征时不会执行强制转换(接收者除外,请参见下一页)。如果存在某种类型 U 的 impl,并且 T 强制 U,那么这并不构成 T 的实现。
下一页说
假设我们有一个函数 foo,它有一个接收者(self、&self 或 &mut self 参数)。如果我们调用 value.foo(),编译器需要确定 Self 的类型,然后才能调用该函数的正确实现。...如果它无法调用此函数(例如,如果该函数的类型错误或没有为 Self 实现特征),则编译器会尝试添加自动引用。这意味着编译器会尝试 <&T>::foo(value) 和 <&mut T>::foo(value)。这称为“autoref”方法调用。
因此,当匹配特征绑定时,Rust 编译器将尝试仅在类型上自动引用/取消引用。另外,rust中的点运算符只是完全限定函数调用的语法糖。因此5.0.try_into().unwrap();将变为f64::try_into(5.0).unwrap();,并且由于TryInto没有实现f64,Rust 将尝试通过调用 来自动引用它&f64::try_into(5.0).unwrap();。现在编译器可以找到TryIntofor 的实现版本&f64,但是参数的类型仍然不匹配:try_intofor&f64需要&f64作为参数类型,而当前调用提供了f64,并且 Rust 编译器在检查特征绑定时无法对参数进行任何强制。因此,特征边界仍然不匹配(&f64不能接受f64参数)并且检查失败。这样你就会看到错误消息。