0
点赞
收藏
分享

微信扫一扫

Rust复杂的表达式解析结果探讨

海滨公园 2022-02-25 阅读 68
rust

在上文Solana项目学习(一):Hello World_biakia0610的专栏-CSDN博客中,我们学习了solana的helloworld例子,在代码最后一部分,有一个非常复杂的表达式:

greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

这里的&mut &mut account.data.borrow_mut()[..] 到底是返回什么呢? 这篇文章会尝试进行详细探讨。

首先,account是solana官方数据类型AccountInfo

#[derive(Clone)]
pub struct AccountInfo<'a> {
    /// Public key of the account
    pub key: &'a Pubkey,
    /// Was the transaction signed by this account's public key?
    pub is_signer: bool,
    /// Is the account writable?
    pub is_writable: bool,
    /// The lamports in the account.  Modifiable by programs.
    pub lamports: Rc<RefCell<&'a mut u64>>,
    /// The data held in this account.  Modifiable by programs.
    pub data: Rc<RefCell<&'a mut [u8]>>,
    /// Program that owns this account
    pub owner: &'a Pubkey,
    /// This account's data contains a loaded program (and is now read-only)
    pub executable: bool,
    /// The epoch at which this account will next owe rent
    pub rent_epoch: Epoch,
}

我们可以看到data是个Rc<RefCell<&'a mut u64>>类型。那么当我们调account.data.borrow_mut()的时候,实际发生了什么呢?

在RC官方文档中有如下描述:

//! `Rc<T>` automatically dereferences to `T` (via the [`Deref`] trait),
//! so you can call `T`'s methods on a value of type [`Rc<T>`][`Rc`]. To avoid name
//! clashes with `T`'s methods, the methods of [`Rc<T>`][`Rc`] itself are associated
//! functions, called using [fully qualified syntax]:

所以account.data.borrow_mut()调用的其实是被RC包裹的RefCell<&mut [u8]>的方法。

下面我们看下RefCell中的borrow_mut()

    #[stable(feature = "rust1", since = "1.0.0")]
    #[inline]
    #[track_caller]
    pub fn borrow_mut(&self) -> RefMut<'_, T> {
        self.try_borrow_mut().expect("already borrowed")
    }

可以看到返回的是一个RefMut类型。因此,account.data.borrow_mut()[..]其实是对RefMut类型做[..]操作,而[..]操作是什么呢?它其实是语法糖,真实的操作是

*(account.data.borrow_mut().index_mut(..))

这时候其实是调用RefMut的index_mut(..)方法,然后找了一圈发现RefMut并没有这个方法。这时候按理说应该会编译报错啊,但是实际是运行成功的。那为什么呢?其实是Rust编译器帮我们智能解析了表达式,下面是Rust官方文档中的描述:

大意就是Rust会对不匹配的表达式进行各种尝试,比如引用、解引用等。

*(account.data.borrow_mut().index_mut(..))

这里虽然RefMut并没有index_mut方法,但是Rust会对RefMut进行解引用,得到内部的&mut [u8],而&mut [u8]是可以执行index_mut方法的,返回的还是个&mut [u8]。因此上面的表达式就变成了

*(&mut [u8])

最终就是一个[u8]类型

因此&mut &mut account.data.borrow_mut()[..]的结果是&mut &mut [u8]。

参考:

​​​​​​rust - Trouble understanding &mut &mut reference - Stack Overflow

Method call expressions - The Rust Reference

IndexMut in std::ops - Rust

举报

相关推荐

0 条评论