Rust区块琏开发——所有权与引用

1.所有权
1.1 在rust语法上,所有权会影响一个对象或者变量的可见性和可变性,rust里面, 一个对象或变量只允许有一个所有者,这对于内存管理来说,可以不用引起很多不必要的麻烦与安全问题。在使用的过程中,这种单线性的设计,只需要关心对象所有者的生命周期,那么就可以对该对象安全性进⾏清晰的管理。
1.2 比如在进行赋值(let x = y)或通过值来传递函数参数(foo(x))的时候,资源的所有权(ownership)会发生转移。按照 Rust 的说法,这被称为资源的移动(move)。在移动资源之后,原来的所有者不能再被使用,这可避免悬挂指针(dangling pointer)的产生,那么就可可以放⼼的对原对象进⾏清理。

 let x : String = "hello".to_string();
 let y = x;
  print!("{:?}",x);

这样做是会报错的:
在这里插入图片描述

2.共享引用和可变引用
2.1 Rust的设计原则是,同⼀作⽤域内,对于某⼀个对象的引⽤,只允许存在两种情况:要么只有⼀个可变引⽤,要么同时存在多个共享引⽤,共享引⽤不允许修改内容,可变引⽤才有修改权限。

共享引用

&
  let x : String = "hello".to_string();
  let mut y = &x;
  y = "w".to_string();
  print!("{:?}",x);

在这里插入图片描述

可变引用

&mut

2.2 rust 与C++的区别在于,C++中有一种引用,并且是可变的,但rust中的类型,如果没有实现Copy trait,那么在此类型的变量赋值、函数入参、函数返回值都是move语义。C++ 11 之后也有move语法。

3.内部可变性
3.1. 如果想要对共享引用修改,rust有明确的语法原则可以赋予共享引⽤修改的权限,由于这个“赋予”⾏为是通过语法明确指定的,在语法设计上并未违反rust的设计原则。但需要通过引⼊Cell与RefCell,引入Cell与RefCell可以理解为一种⾛后⻔的⾏为,只是对这种行为进行了严格备案的。

3.2. RefCell相⽐Cell,内部维护了⼀个包装对象的引⽤计数,当通过 RefCell.borrow 获取⼀个共享 引⽤时,内部引⽤计数加⼀,当获取的引⽤离开作⽤域时,内部引⽤计数减⼀,当RefCell.borrow_mut 获取⼀个可变引⽤时,⾸先检测引⽤技数是否为 0,如果为 0,正常返回, 如果不为 0,直接 panic,其实 RefCell.borrow 时也会做类似的检测,当已经获取了可变引⽤也 是直接 panic, 当然为了避免 panic,我们可以⽤ RefCell.try_borrow 和RefCell.try_borrow_mut 来获取⼀个 Result 类型。 由于Cell并未引⼊引⽤计数,所以 Cell 需要满⾜ T:Copy

3.3. 对于Cell⽽⾔,通过 get 获取到的是原有对象的拷⻉, set 则使⽤新的对象替换原有⽼对象。RefCell 没有这个约束,它的操作都是通过返回可变指针完成。 由于实现机制上的差别,Cell只能包装 Copy 类型,⽽RefCell能够包装任意类型,所以在不确定 ⼀个对象是否实现了 Copy 时,应该选择RefCell。 由于上述差异,RefCell更加常⽤,通常的做法是配合Rc,组成 Rc<RefCell>

3.4.Cell与RefCell都没有实现 Sync(异步) ,所以这两种类型均只能⽤于单线程。
3.5 RefCell与共享线程的例子

thread_local!
{
    
    
    pub static UID_INDEX: RefCell<u128> = RefCell::new(1);
    pub static USERS :RefCell<BTreeMap<Principal,User>> = RefCell::new(BTreeMap::new());
}

fn user_login(caller : &str) -> UserInfo
{
    
    
    USERS.with(|keys_users_ref|
    {
    
    
        let mut write = keys_users_ref.borrow_mut();
        let pid = caller.to_string();
        match write.entry(pid) 
        {
    
    
            Vacant(empty_store_entry) => 
            {
    
    
                //add uid index
                let id = UID_INDEX.with(|counter_ref| 
                    {
    
    
                        let mut writer = counter_ref.borrow_mut();
                        *writer += 1;
                        *writer
                    });
                
                //nft initialize to null
                let nft:NFT = NFT {
    
     canister_id: String::new(), standard: String::new(), token_index:String::new()};
                let user_info : UserInfo = UserInfo {
    
     avatar:String::new(),email:String::new()};
                write.insert(caller.to_string(), User {
    
     avatar:user_info.avatar.clone(), 
                    nft: nft, email: user_info.email.clone(), planets:Vec::new(), subscribes:Vec::new(), attribute:Vec::new()});
                user_info
            },
            Occupied(store) =>
            {
    
    
                let user = store.get();
                UserInfo{
    
    avatar:user.avatar.clone(),email:user.email.clone()}
            }
        }
    })

}

猜你喜欢

转载自blog.csdn.net/matt45m/article/details/125046581