Rust 什么是生锈';什么是精确的自动解引用规则?
我正在学习/试验锈菌,在这门语言中我发现的所有优雅中,有一个特性让我困惑,似乎完全不合适 Rust在进行方法调用时自动取消引用指针。我做了一些测试来确定确切的行为: 结构X{val:i32} impl std::ops::Deref for X{ 类型目标=i32; fn deref(&self)->&i32{&self.val} } 特征M{fn M(自我);} i32的impl M{fn M(self){println!(“i32::M()”);} 对于X{fn M(self){println!(“X::M()”);}} impl M for&X{fn M(self){println!(“&X::M()”);} &X{fn M(self){println!(“&X::M()”);} 对&&&X{fn M(self){println!(“&&X::M()”)} 特征RefM{fn RefM(&self);} i32{fn RefM(&self){println!(“i32::RefM()”);} impl RefM for X{fn RefM(&self){println!(“X::RefM()”);} impl RefM for&X{fn RefM(&self){println!(“&X::RefM()”);} &X的impl RefM{fn RefM(&self){println!(“&X::RefM()”);} 对&&X{fn RefM(&self){println!(“&&X::RefM()”)}的impl RefM 结构Y{val:i32} impl std::ops::Deref for Y{ 类型目标=i32; fn deref(&self)->&i32{&self.val} } 结构Z{val:Y} impl std::ops::Deref for Z{ 类型目标=Y; fn deref(&self)->&Y{&self.val} } #[派生(克隆、复制)] 结构A; 对于{fn M(self){println!(“A::M()”);}} 对&&A{fn M(self){println!(“&&A::M()”)}的impl M 对{fn RefM(&self){println!(“A::RefM()”);}的impl RefM 对&&A{fn RefM(&self){println!(“&&A::RefM()”)}的impl RefM fn main(){ //我将使用@表示点运算符的左侧 (*X{val:42}).m();//i32::m(),Self==@ X{val:42}.m();//X::m(),Self==@ (&X{val:42}).m();/&X::m(),Self==@ (&&X{val:42}).m();/&&X::m(),Self==@ (&&&X{val:42}).m();/&&X:m(),Self==@ (&&&&X{val:42}).m();//&&X::m(),Self==*@ (&&&&&&X{val:42}).m();//&&&X::m(),Self==**@ println!(“---------------------------”)号; (*X{val:42}).refm();//i32::refm(),Self==@ X{val:42}.refm();//X::refm(),Self==@ (&X{val:42}).refm();//X::refm(),Self==*@ (&&X{val:42}).refm();//&X::refm(),Self==*@ (&&&X{val:42}).refm();//&&X::refm(),Self==*@ (&&&&X{val:42}).refm();//&&X::refm(),Self==*@ (&&&&&X{val:42}).refm();//&&X::refm(),Self==**@ println!(“---------------------------”)号; Y{val:42}.refm();//i32::refm(),Self==*@ Z{val:Y{val:42}}.refm();//i32::refm(),Self==**@ println!(“---------------------------”)号; A.m();//A::m(),Self==@ //如果没有复制特性,(&A).m()将是一个编译错误: //无法移出借用的内容 (&A).m();//A::m(),Self==*@ (&&A).m();//&&A::m(),Self==&@ (&&&A).m();//&&A::m(),Self==@ A.refm();//A::refm(),Self==@ (&A).refm();//A::refm(),Self==*@ (&&A).refm();//A::refm(),Self==**@ (&&&A.refm();//&&A::refm(),Self==@ } () 因此,似乎或多或少:Rust 什么是生锈';什么是精确的自动解引用规则?,rust,reference,language-lawyer,Rust,Reference,Language Lawyer,我正在学习/试验锈菌,在这门语言中我发现的所有优雅中,有一个特性让我困惑,似乎完全不合适 Rust在进行方法调用时自动取消引用指针。我做了一些测试来确定确切的行为: 结构X{val:i32} impl std::ops::Deref for X{ 类型目标=i32; fn deref(&self)->&i32{&self.val} } 特征M{fn M(自我);} i32的impl M{fn M(self){println!(“i32::M()”);} 对于X{fn M(self){printl
- 编译器将插入调用方法所需的尽可能多的解引用运算符
- 编译器在解析使用
声明的方法时(通过引用调用):&self
- 首先尝试调用
self
- 然后尝试调用
self的确切类型
- 然后,尝试插入匹配所需的尽可能多的解引用运算符
- 首先尝试调用
- 对于类型
使用T
(按值调用)声明的方法的行为就好像它们对于类型self
使用&T
(按引用调用)声明,并且在引用时调用点运算符左侧的任何对象一样&self
- 上述规则首先使用原始的内置解引用进行尝试,如果不匹配,则使用重载with
traitDeref
准确的自动取消引用规则是什么?有人能给出这种设计决策的正式理由吗?您的伪代码非常正确。对于本例,假设我们有一个方法调用
foo.bar()
wherefoo:T
。我将使用(FQS)来明确调用方法的类型,例如A::bar(foo)
或A::bar(&***foo)
。我要写一堆随机的大写字母,每一个都是任意的类型/特征,除了T
总是调用方法的原始变量foo
的类型
算法的核心是:
- 对于每个
(即,设置U
,然后设置U=T
,…)U=*T
- 如果有一种方法
,其中接收器类型(方法中的bar
类型)与self
完全匹配,则使用它()U
- 否则,添加一个自动引用(获取接收器的
或&
),如果某个方法的接收器匹配&mut
,则使用它()&U
自我
类型,即impl。。。对于Foo{fn method(&self){}
在匹配方法时会考虑&Foo
,而fn method2(&mut self)
在匹配时会考虑&mut Foo
如果在内部步骤中存在多个有效的特征方法(即,在1.或2.中的每个步骤中只能有零个或一个有效的特征方法,但每个步骤都可以有一个有效的特征方法:1中的一个将首先被采用),并且固有方法优先于
[⟪i32⟫, &i32, &mut i32]
[⟪X⟫, &X, &mut X,
i32, &i32, &mut i32]
[⟪&X⟫, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[⟪&&X⟫, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[⟪&&&X⟫, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[&&&&X, &&&&&X, &mut &&&&X,
⟪&&&X⟫, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[&&&&&X, &&&&&&X, &mut &&&&&X,
&&&&X, &&&&&X, &mut &&&&X,
⟪&&&X⟫, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[i32, ⟪&i32⟫, &mut i32]
[X, ⟪&X⟫, &mut X,
i32, &i32, &mut i32]
[⟪&X⟫, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[⟪&&X⟫, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[⟪&&&X⟫, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[⟪&&&&X⟫, &&&&&X, &mut &&&&X,
&&&X, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[&&&&&X, &&&&&&X, &mut &&&&&X,
⟪&&&&X⟫, &&&&&X, &mut &&&&X,
&&&X, &&&&X, &mut &&&X,
&&X, &&&X, &mut &&X,
&X, &&X, &mut &X,
X, &X, &mut X,
i32, &i32, &mut i32]
[Y, &Y, &mut Y,
i32, ⟪&i32⟫, &mut i32]
[Z, &Z, &mut Z,
Y, &Y, &mut Y,
i32, ⟪&i32⟫, &mut i32]
[⟪A⟫, &A, &mut A]
[&A, &&A, &mut &A,
⟪A⟫, &A, &mut A]
[&&A, ⟪&&&A⟫, &mut &&A,
&A, &&A, &mut &A,
A, &A, &mut A]
[⟪&&&A⟫, &&&&A, &mut &&&A,
&&A, &&&A, &mut &&A,
&A, &&A, &mut &A,
A, &A, &mut A]
[A, ⟪&A⟫, &mut A]
[⟪&A⟫, &&A, &mut &A,
A, &A, &mut A]
[&&A, &&&A, &mut &&A,
⟪&A⟫, &&A, &mut &A,
A, &A, &mut A]
[&&&A, ⟪&&&&A⟫, &mut &&&A,
&&A, &&&A, &mut &&A,
&A, &&A, &mut &A,
A, &A, &mut A]
(*X{val:42}).refm(); // i32::refm() , Self == @
X{val:42}.refm(); // X::refm() , Self == @
(&X{val:42}).refm(); // X::refm() , Self == *@
(&&X{val:42}).refm(); // &X::refm() , Self == *@
(&&&X{val:42}).refm(); // &&X::refm() , Self == *@
(&&&&X{val:42}).refm(); // &&&X::refm(), Self == *@
(&&&&&X{val:42}).refm(); // &&&X::refm(), Self == **@
trait RefM { fn refm(&self); }
impl RefM for i32 { fn refm(&self) { println!("i32::refm()"); } }
// converted to: fn refm(&i32 ) { println!("i32::refm()"); }
// => type of 'self' : i32
// => type of parameter: &i32
impl RefM for X { fn refm(&self) { println!("X::refm()"); } }
// converted to: fn refm(&X ) { println!("X::refm()"); }
// => type of 'self' : X
// => type of parameter: &X
impl RefM for &X { fn refm(&self) { println!("&X::refm()"); } }
// converted to: fn refm(&&X ) { println!("&X::refm()"); }
// => type of 'self' : &X
// => type of parameter: &&X
impl RefM for &&X { fn refm(&self) { println!("&&X::refm()"); } }
// converted to: fn refm(&&&X ) { println!("&&X::refm()"); }
// => type of 'self' : &&X
// => type of parameter: &&&X
impl RefM for &&&X { fn refm(&self) { println!("&&&X::refm()"); } }
// converted to: fn refm(&&&&X) { println!("&&&X::refm()"); }
// => type of 'self' : &&&X
// => type of parameter: &&&&X