首页 > 解决方案 > 无法理解 &mut &mut 参考

问题描述

我正在关注教程,但无法理解以下代码:

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

wheremail_account是一个结构体,.serialize()是一个派生自Borsh Serialize的方法。

需要注意的另一件事是,它是solana_program 板条箱account中的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]?)

标签: rust

解决方案


所以,我想,你有多个问题:

  1. 我不明白为什么添加 [..] 很重要?

  2. 我也无法理解如何将 &mut &mut 添加到 account.data.borrow_mut()[..] 中创建一个 u8 切片。这是如何转换为u8的?

正如您在问题 1 的答案中看到的那样,这些问题有点交织在一起。

问题 1

当我们查看有关某些索引案例的文档时,我们看到,

account.data.borrow_mut()[..]

是糖

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

为什么这是一个有效的表达方式?

..是 的简写RangeFull

RangeFull有一个实现SliceIndex<[u8]>

通过这个全面的实现,我们得到一个IndexMut<RangeFull> for [u8],它提供

fn index_mut(&mut [u8], index: RangeFull) -> &mut [u8]

现在,其他答案和评论中提到的解除引用强制和/或自动解除引用开始生效。

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

RefMut<&mut [u8]>实现DerefMut具有Deref<Target = &mut [u8]>超级特征的工具。

并以as 超级特征&mut [u8]实现。DerefMutDeref<Target = [u8]>

参考中所述,编译器现在将获取接收器表达式并重复取消引用它,因此它会获得候选类型列表。它还为因取消引用而产生的每种类型添加引用类型和可变引用类型到候选类型列表中。从这个候选类型中,它选择一个提供调用方法的类型。

  1. RefMut<&mut [u8]>使用account.data.borrow_mut()
  2. &RefMut<&mut [u8]>
  3. &mut RefMut<&mut [u8]>
  4. &mut [u8]使用*account.data.borrow_mut().deref_mut()
  5. &&mut [u8]
  6. &mut &mut [u8]
  7. [u8]使用*(*account.data.borrow_mut().deref_mut())
  8. &[u8]
  9. &mut [u8]

(在 7 中,我们正在取消引用指针类型&mut [u8],因此不DerefMut使用 Trait。)

此列表中提供index_mut()方法的第一个(也是唯一一个)类型是&mut [u8],通过IndexMut<FullRange>实现 for [u8],因此&mut [u8]被选为接收器类型。的返回类型index_mut()也是&mut [u8]如此。

所以现在,我们希望能理解,

*(account.data.borrow_mut().index_mut(..))[u8]

因此:

问题2

&mut &mut account.data.borrow_mut()[..]

有类型&mut &mut [u8]

附录

&mut &mut [u8]需要&mut [u8]一个Write 实现。

serialize

pub fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>

需要一个类型的参数&mut W,其中W实现Write

W对类型实现的值的引用Write需要是可变的,因为我们想要跟踪类型值中的实际写入位置W。在&mut [u8]我们简单地改变引用以从底层切片中的不同位置开始的情况下,我们需要对可变引用的可变引用,因为我们想要改变可变引用本身,而不仅仅是底层数据。

附录 2

只需使用

mail_account.serialize(&mut *account.data.borrow_mut())?;

推荐阅读