假设我想在引用上实现转换。在这种情况下,它是从&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();
}
(是的,当然这是一个毫无意义和愚蠢的例子,但它有助于简化问题(
现在,主方法中的第二行,通过手动借用,成功了。然而,主方法中的第一行,在没有手动借用的情况下,由于以下错误而失败:
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
游乐场
为什么自动借款在这里不起作用?
正如错误消息所示,问题是the trait bound Foo: From<{float}> is not satisfied
。当匹配特征时,Rust不会执行任何强制,而是探测合适的方法。这实际上记录在Rustonomicon中,读取
请注意,在匹配特征时,我们不执行强制(接收器除外,请参阅下一页(。如果某个类型U有一个impl,而T强制为U,则不构成T.的实现
下一页显示
假设我们有一个函数foo,它有一个接收器(self、&self或&mut-self参数(。如果我们调用value.foo((,编译器需要确定Self是什么类型,然后才能调用函数的正确实现。。。如果它不能调用这个函数(例如,如果函数的类型错误,或者没有为Self实现特性(,那么编译器会尝试添加一个自动引用。这意味着编译器尝试<amp;T>:foo(值(和<amp;mut T>:foo(值(。这被称为";autoref";方法调用。
因此,当匹配特征绑定时,Rust编译器将尝试仅对类型进行自动引用/取消引用。此外,rust中的点运算符只是完全限定函数调用的语法糖。因此,5.0.try_into().unwrap();
将变为f64::try_into(5.0).unwrap();
,并且由于TryInto
没有为f64
实现,因此Rust将尝试通过调用&f64::try_into(5.0).unwrap();
来自动引用它。现在编译器可以找到为&f64
实现的TryInto
版本,但参数类型仍然不匹配:&f64
的try_into
需要&f64
作为参数类型,而当前调用提供f64
,Rust编译器在检查特征绑定时不能对参数进行任何强制。因此,特征绑定仍然不匹配(&f64
不能接受f64
参数(,并且检查失败。因此,您将看到错误消息。