Rust方法receiver的不同形式

在Rust语言中, 一个方法的receiver默认并且总是正确的选择,即是:&self, &mut self , 偶尔也会用一下:self ; 同时Rust还允许如下形式的方法receiver: Box<Self>, Rc<Self>, Arc<Self> , 我在rust1.88.0 2024 edition stable 版本下做了代码实验, 以上形式Rust都支持,编译通过。

use std::{rc::Rc, sync::Arc};
struct At(u8);
impl At {
    fn pb(self:Box<At>){
        println!("Box: {}", self.0)
    }
    fn pr(self:Rc<At>){
        println!("Rc: {}", self.0)
    }
    fn pa(self:Arc<At>){
        println!("Arc: {}", self.0)
    }
    fn p(&self){
        println!("raw:{}", self.0)
    }
}
fn main() {
    let p = At(100);
    let pr = Rc::new(At(101));
    let pb = Box::new(At(102));
    let pa = Arc::new(At(103));
    
    p.p();
    pr.pr();
    //pr.p(); //error: borrow of moved value.
    pb.pb();
    //pb.p(); //error: borrow of moved value.
    pa.pa();
    //pa.p(); //error: borrow of moved value.
}

Rust还有一个RFC #44874 , arbitrary_self_types feature, 大致意思是说:允许将一个自定义包裹类型作为方法的receiver, 在当前Rust版本,我仿照Box编写了一个简易版本的智能指针MyBox, 编译运行通过后, 我将MyBox<自定义类型>作为一个方法的receiver, 编译没通过,看来这个feature还没有stable, IDE的报错提示详细信息如下:

`MyBox<INT>` cannot be used as the type of `self`
 without the `arbitrary_self_types` feature
see issue #44874 
<https://github.com/rust-lang/rust/issues/44874> for more information
consider changing to `self`, `&self`, `&mut self`, 
or a type implementing `Receiver`
 such as `self: Box<Self>`, `self: Rc<Self>`, 
 or `self: Arc<Self>`rustc(Click for full compiler diagnostic)
   mybox_as_receiver  struct MyBox<T>(T)

权威资料说:作为方法的receiver : &self和&mut self 几乎总是正确的选择;即使遇到智能指针包裹形式的receiver,如: Box<Self>, Rc<Self>, Arc<Self>等, Rust也可以通过自动”解引用(Deref和DerefMut)” ,将其转化成&self或&mut self形式, 所以如无特别的理由和需求, 我们自己定义的方法的receiver采用原始直接形式传递即可,不必要采用包裹类型传递。下面是一个自定义类型作为方法receiver的实验:

//一个自定义类型作为方法的receiver.
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T>{
    fn new(x:T)->MyBox<T>{
        MyBox(x)
    }
}
//还可以同时实现DerefMut trait来重载可变引用的*运算符。
//若是有需要清理的资源,还可以同时实现Drop trait.
impl<T> Deref for MyBox<T>{
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
struct INT(u32);
impl INT{
    fn add(self:MyBox<Self>, y:u32) -> u32{
        (*self).0 +y
    }
}
fn main() {
    let x =5;
    let y = MyBox::new(x);
    assert_eq!(5, x);
    assert_eq!(5,*y);
}

【编译报错】

> cargo build                                                                                                        
   Compiling mybox_as_receiver v0.1.0 (D:Workspace_Projs_Source_Code
ust_projsmybox_as_receiver)                                                                                
error[E0658]: `MyBox<INT>` cannot be used as the type of `self` without the `arbitrary_self_types` feature                                                                         
  --> srcmain.rs:25:17                                                                                                                                                            
   |                                                                                                                                                                               
25 |     fn add(self:MyBox<Self>, y:u32) -> u32{                                                                                                                                   
   |                 ^^^^^^^^^^^                                                                                                                                                   
   |                                                                                                                                                                               
   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information                                                                                  
   = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`                  


For more information about this error, try `rustc --explain E0658`.                                                                                                                
error: could not compile `mybox_as_receiver` (bin "mybox_as_receiver") due to 1 previous error  

我个人认为,上面6种方法receiver形式已经足够用了,没有必要将自定义包裹类型作为方法的receiver,Rust原有的智能指针类型已经足够了; 还不如自定义一个类型,然后为这个类型实现相应的方法呢!没有必要将receiver搞得太复杂!

最后再强调一下这6种可用形式: self, &self, &mut self, Box<Self>, Rc<Self>, Arc<Self>; 注意后3种receiver中的S是大写的呦!大写Self代表一个类型,小写self代表这个类型的一个实例或实例的引用。

注意:个人学习随笔,水平有限,若有谬误,望请海涵指正!

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容