所以,我猜你有多个问题:
-
我不明白的是为什么要添加[..]?
-
我也不太理解如何通过在account.data.borrow_mut()[..]中添加&mut &mut来创建u8切片。这是如何转换为u8的?
这些问题有点相互交织,正如在第一个问题的答案中所看到的。
问题1
当我们查看关于某些索引情况的文档时,我们可以看到,
account.data.borrow_mut()[..]
is sugar for
*(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]>
是其超级特质。
&mut [u8]
通过 DerefMut
实现,其超级特质为 Deref<Target = [u8]>
。
如 参考文献 中所述,编译器将对接收表达式进行重复解引用,以获取候选类型列表。它还会为每个从解引用中得出的类型添加引用类型和可变引用类型,并将其添加到候选类型列表中。从这些候选类型中选择一个提供要调用的方法。
- 使用
account.data.borrow_mut()
的 RefMut<&mut [u8]>
&RefMut<&mut [u8]>
&mut RefMut<&mut [u8]>
- 使用
*account.data.borrow_mut().deref_mut()
的 &mut [u8]
&&mut [u8]
&mut &mut [u8]
- 使用
*(*account.data.borrow_mut().deref_mut())
的 [u8]
&[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]
。
因此:
问题2
&mut &mut account.data.borrow_mut()[..]
类型为&mut &mut [u8]
。
补充
&mut [u8]
具有Write
实现,因此需要&mut &mut [u8]
。
并且序列化
。
pub fn serialize<W: Write>(&self, writer: &mut W) -> Result<()>
需要使用类型为&mut W
的参数,其中W
实现了Write
。
对于实现Write
的类型W
的值的引用需要是可变的,因为我们想要跟踪类型为W
的值中的实际写入位置。对于&mut [u8]
的情况,我们只需更改引用以从基础切片的不同位置开始,因此我们需要一个可变引用来更改可变引用本身,而不仅仅是底层数据。
补充2
只需使用
mail_account.serialize(&mut *account.data.borrow_mut())?;
&mut *account.data.borrow_mut()
可以工作。 - Ibraheem Ahmed