Rust block chain development - ownership and reference

1. Ownership
1.1 In rust syntax, ownership will affect the visibility and mutability of an object or variable. In rust, an object or variable is only allowed to have one owner, which does not cause many unnecessary problems for memory management. troubles and safety issues. In the process of use, this single-line design only needs to care about the life cycle of the object owner, so the security of the object can be clearly managed.
1.2 For example, when assigning a value (let x = y) or passing a function parameter by value (foo(x)), the ownership of the resource (ownership) will be transferred. In Rust parlance, this is called moving a resource. After the resource is moved, the original owner can no longer be used, which can avoid the generation of dangling pointers, so the original object can be cleaned up with confidence.

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

Doing so will result in an error:
insert image description here

2. Shared references and mutable references
2.1 The design principle of Rust is that in the same scope, there are only two situations allowed for a reference to an object: either there is only one mutable reference, or there are multiple references at the same time. shared references, shared references are not allowed to modify the content, and mutable references only have modification permissions.

shared reference

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

insert image description here

mutable reference

&mut

2.2 The difference between rust and C++ is that there is a kind of reference in C++, and it is variable, but if the type in rust does not implement the Copy trait, then the variable assignment, function input parameter, and function return value of this type are move semantics. There is also a move syntax after C++11.

3. Internal mutability
3.1. If you want to modify shared references, rust has a clear grammatical principle to grant permission to modify shared references. Since this "granting" behavior is clearly specified by the grammar, there is no grammatical design. Violates the design principles of rust. However, it is necessary to introduce Cell and RefCell. The introduction of Cell and RefCell can be understood as a kind of backdoor behavior, but this behavior is strictly recorded.

3.2. Compared with Cell, RefCell internally maintains a reference count of a wrapper object. When a shared reference is obtained through RefCell.borrow, the internal reference count is increased by one. When the obtained reference leaves the scope, The internal reference count is reduced by one. When RefCell.borrow_mut obtains a variable reference, it first checks whether the reference count is 0. If it is 0, it returns normally. If it is not 0, it panics directly. In fact, RefCell.borrow Similar detection will be done when the variable reference has been obtained. Of course, in order to avoid panic, we can use RefCell.try_borrow and RefCell.try_borrow_mut to obtain a Result type. Since Cell does not introduce reference counting, Cell needs to satisfy T:Copy

3.3. For Cell, what is obtained through get is a copy of the original object, and set uses a new object to replace the original object. RefCell does not have this constraint, and its operations are all done by returning variable pointers. Due to the difference in the implementation mechanism, Cell can only wrap the Copy type, while RefCell can wrap any type, so when you are not sure whether an object implements Copy, you should choose RefCell. Due to the above differences, RefCell is more commonly used, and the usual practice is to cooperate with Rc to form Rc<RefCell>

3.4. Both Cell and RefCell do not implement Sync (asynchronous), so these two types can only be used for single thread.
3.5 Examples of RefCell and shared threads

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

}

Guess you like

Origin blog.csdn.net/matt45m/article/details/125046581
Recommended