标签:mut account methods borrow pub Rust 解析 data 表达式
在上文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官方文档中的描述:
When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method. This requires a more complex lookup process than for other functions, since there may be a number of possible methods to call. The following procedure is used:
The first step is to build a list of candidate receiver types. Obtain these by repeatedly dereferencing the receiver expression's type, adding each type encountered to the list, then finally attempting an unsized coercion at the end, and adding the result type if that is successful. Then, for each candidate
T
, add&T
and&mut T
to the list immediately afterT
.For instance, if the receiver has type
Box<[i32;2]>
, then the candidate types will beBox<[i32;2]>
,&Box<[i32;2]>
,&mut Box<[i32;2]>
,[i32; 2]
(by dereferencing),&[i32; 2]
,&mut [i32; 2]
,[i32]
(by unsized coercion),&[i32]
, and finally&mut [i32]
.Then, for each candidate type
T
, search for a visible method with a receiver of that type in the following places:
T
's inherent methods (methods implemented directly onT
).- Any of the methods provided by a visible trait implemented by
T
. IfT
is a type parameter, methods provided by trait bounds onT
are looked up first. Then all remaining methods in scope are looked up.
大意就是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
标签:mut,account,methods,borrow,pub,Rust,解析,data,表达式 来源: https://blog.csdn.net/biakia0610/article/details/123131164
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。