rust - 为什么 (*x).into() 需要显式取消引用,而 x.my_into() 不需要?
问题描述
在阅读了方法调用表达式、解引用运算符、方法查找和自动解引用之后,我认为我对这个主题有了很好的理解;但后来我遇到了一种情况,我希望自动取消引用会发生,而实际上它并没有发生。
示例如下。
#[derive(Clone, Copy, Debug)]
struct Foo();
impl Into<&'static str> for Foo {
fn into(self) -> &'static str {
"<Foo as Into>::into"
}
}
fn vec_into<F: Copy + Into<T>, T>(slice: &[F]) -> Vec<T> {
slice.iter().map(|x| (*x).into()).collect()
}
fn main() {
let array = [Foo(), Foo(), Foo()];
let vec = vec_into::<_, &'static str>(&array);
println!("{:?}", vec);
}
上面的代码有效,但我认为不需要(*x).into()
函数中的显式取消引用。vec_into
我的理由是,因为x: &Foo
, thenx.into()
会尝试找到接受 type &Foo
, &&Foo
, &mut &Foo
, Foo
, &Foo
, 的方法&mut Foo
。
这是因为存在解引用链&Foo
→ Foo
,并且对于U
该链中的每个,我们还插入&U
and &mut U
。
我的直觉得到以下事实的证实:以下代码也有效,没有任何明确的取消引用。
#[derive(Clone, Copy, Debug)]
struct Foo();
trait MyInto<T> {
fn my_into(self) -> T;
}
impl MyInto<&'static str> for Foo {
fn my_into(self) -> &'static str {
"<Foo as MyInto>::my_into"
}
}
fn vec_my_into<F: Copy + MyInto<T>, T>(slice: &[F]) -> Vec<T> {
slice.iter().map(|x| x.my_into()).collect()
}
fn main() {
let array = [Foo(), Foo(), Foo()];
let my_vec = vec_my_into(&array);
println!("{:?}", my_vec);
}
x: &Foo
为了调用方法,这里被隐式取消引用<Foo as MyInto<&'static str>>::my_into
。
一个更小的例子
鉴于 和 的上述定义Foo
,MyInto
代码
let result: &str = (&Foo()).my_into()
有效,但是
let result: &str = (&Foo()).into()
无法编译并出现错误
error[E0277]: the trait bound `&str: std::convert::From<&Foo>` is not satisfied
--> src/bin/into.rs:34:33
|
34 | let result: &str = (&Foo()).into();
| ^^^^ the trait `std::convert::From<&Foo>` is not implemented for `&str`
|
= note: required because of the requirements on the impl of `std::convert::Into<&str>` for `&Foo`
解决方案
正如您所描述的,Rust 非常准确地执行方法查找,它会立即找到一个候选者.into()
——全面实现
impl<T, U> Into<U> for T
where
U: From<T>,
{
fn into(self) -> U {
U::from(self)
}
}
这个实现满足了候选方法的所有要求——它是可见的、在范围内并为 type 定义的&Foo
,因为它是为任何type定义的T
。一旦编译器选择了这个候选者,它就会注意到U
不满足特征边界,并发出您看到的错误。
情况MyInto
完全不同,因为您没有提供基于From
. 如果你这样做,你会得到同样的错误。
可以说,如果不满足特征边界,编译器应该跳过一揽子实现,并继续使用候选类型列表,直到找到更合适的类型。语言规范在这一点上实际上并不完全清楚,但从错误中我们可以清楚地看出编译器实际上做了什么。
推荐阅读
- forms - redux-form和handleSubmit,onSubmit乱码
- jspm - 获取 jspm_packages/npm/aurelia-bootstrapper@1.0.1.js 404(未找到)
- sql - 添加一年至今
- ruby-on-rails - Rails 将属性添加到活动记录结果
- kotlin - 在 KotlinJS 中访问“导出默认值”的正确方法是什么
- c# - Asp.Net Core 2 Razor AddPageRoute:如何将 id 或其他信息传递给模型?
- c# - ASP.Net Core 2.0 关闭超时,使用 2 分钟很长的时间会出现什么问题?
- python - 每次我想启动 Python IDLE 时,它都会加载
- ruby-on-rails - 如何将 FactoryBot 与只读数据库一起使用
- excel - Sharepoint 和 Excel VBA 集成失败