Rust 什么是生锈';什么是精确的自动解引用规则?

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

我正在学习/试验锈菌,在这门语言中我发现的所有优雅中,有一个特性让我困惑,似乎完全不合适

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==@ } ()

因此,似乎或多或少:

  • 编译器将插入调用方法所需的尽可能多的解引用运算符
  • 编译器在解析使用
    &self
    声明的方法时(通过引用调用):
    • 首先尝试调用
      self
    • 然后尝试调用
      self的确切类型
    • 然后,尝试插入匹配所需的尽可能多的解引用运算符
  • 对于类型
    T
    使用
    self
    (按值调用)声明的方法的行为就好像它们对于类型
    &T
    使用
    &self
    (按引用调用)声明,并且在引用时调用点运算符左侧的任何对象一样
  • 上述规则首先使用原始的内置解引用进行尝试,如果不匹配,则使用重载with
    Deref
    trait

准确的自动取消引用规则是什么?有人能给出这种设计决策的正式理由吗?

您的伪代码非常正确。对于本例,假设我们有一个方法调用
foo.bar()
where
foo: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