我正在学习本教程,但无法理解以下代码:
mail_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
Run Code Online (Sandbox Code Playgroud)
其中mail_account是一个结构体,是从Borsh Serialize.serialize()派生的方法。
另一件需要注意的事情是,它account是来自 solana_program 箱的AccountInfodata结构,其类型为:Rc<RefCell<&'a mut [u8]>>
作者对代码的解释如下:
您可能会注意到这个棘手的
&mut &mut account.data.borrow_mut()[..]表达方式。该serialize()方法将对可变切片的引用作为u8参数,该borrow_mut()方法返回一个RefMut. 我们无法传递RefMut给需要切片的方法,因此我们采用一个可变切片,其中RefMut返回一个可变切片u8
我所理解的是,我们想要将当前mail_account结构写入account.data,这就是我们借用对 的可变引用的原因account.data。我不明白的是为什么添加 很重要[..]?serialize()我认为这与期待切片有关。
我也无法理解添加&mut &mut到如何account.data.borrow_mut()[..]创建u8. 这是如何转换成的u8?对我来说,它似乎只是向原始引用添加了额外的可变引用。(类型如何从 变为RefMut?&[u32])
所以,我想您有多个问题:
我不明白的是为什么添加 [..] 很重要?
我也无法理解如何将 &mut &mut 添加到 account.data.borrow_mut()[..] 创建 u8 的切片。这是如何转换为 u8 的?
这些问题有点交织在一起,正如您在问题 1 的回答中看到的那样。
当我们查看有关某些索引案例的文档时,我们发现,
account.data.borrow_mut()[..]
Run Code Online (Sandbox Code Playgroud)
是糖吗
*(account.data.borrow_mut().index_mut(..))
Run Code Online (Sandbox Code Playgroud)
为什么这是一个有效的表达?
..是 的简写RangeFull。
RangeFull有一个实现SliceIndex<[u8]>。
通过这个一揽子实现,我们得到了一个IndexMut<RangeFull> for [u8],它提供了
fn index_mut(&mut [u8], index: RangeFull) -> &mut [u8]
Run Code Online (Sandbox Code Playgroud)
现在,其他答案和评论中提到的取消引用强制和/或自动取消引用开始生效。
account.data.borrow_mut().index_mut(..)
Run Code Online (Sandbox Code Playgroud)
并RefMut<&mut [u8]>实现了DerefMut具有Deref<Target = &mut [u8]>超级特征的功能。
并以超级特质&mut [u8]实现。DerefMutDeref<Target = [u8]>
正如参考文献中提到的,编译器现在将获取接收者表达式并重复取消引用它,因此它会获得候选类型的列表。它还为因取消引用而产生的每种类型将引用类型和可变引用类型添加到候选类型列表中。它从这个候选类型中选择一个提供要调用的方法的类型。
RefMut<&mut [u8]>使用account.data.borrow_mut()&RefMut<&mut [u8]>&mut RefMut<&mut [u8]>&mut [u8]使用*account.data.borrow_mut().deref_mut()&&mut [u8]&mut &mut [u8][u8]使用*(*account.data.borrow_mut().deref_mut())&[u8]&mut [u8](在 7. 中,我们取消引用指针类型&mut [u8],因此不DerefMut使用 Trait。)
此列表中提供方法的第一个(也是唯一一个)类型index_mut()是&mut [u8],通过IndexMut<FullRange>的实现[u8],因此&mut [u8]被选为接收器类型。的返回类型index_mut()也是&mut [u8]如此。
所以现在,我们希望能够理解,
*(account.data.borrow_mut().index_mut(..))是[u8]。
因此:
&mut &mut account.data.borrow_mut()[..]
Run Code Online (Sandbox Code Playgroud)
有类型&mut &mut [u8].
&mut &mut [u8]需要&mut [u8]实施Write
。
pub fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>
Run Code Online (Sandbox Code Playgroud)
需要一个类型&mut W为Wimplements的参数Write。
W对 type实现的值的引用Write需要可变,因为我们希望跟踪 type 值中的实际写入位置W。在我们简单地更改引用以从底层切片中的不同位置开始的情况下&mut [u8],因此我们需要对可变引用的可变引用,因为我们想要更改可变引用本身,而不仅仅是底层数据。
只需使用
pub fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>
Run Code Online (Sandbox Code Playgroud)