在 Rust 中针对带有引用字段 struct 的深拷贝
在项目开发时,针对深拷贝的优化方案思考。
首先观察下面的 struct 结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
#[derive(Default, Debug, Clone)]
pub struct CompressedPostingListView<'a, TW>
where
TW: QuantizedWeight,
{
pub row_ids_compressed: &'a [u8],
pub simple_blocks: &'a [SimpleCompressedPostingBlock<TW>],
pub extended_blocks: &'a [ExtendedCompressedPostingBlock<TW>],
pub compressed_block_type: CompressedBlockType,
pub quantization_params: Option<QuantizedParam>,
pub row_ids_count: RowId,
pub max_row_id: Option<RowId>,
}
在这段结构体中可以看到有三个字段是引用,并且显式的标注了生命周期,观察 struct 实例在 Clone 时的行为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#[test]
fn test_compressed_posting_list_view_clone() {
let row_ids_compressed: Vec<u8> = vec![1, 2, 3]; // 使用 Vec 而不是 &[u8],因为 Vec 是可变的
let row_ids_slice: &[u8] = &row_ids_compressed[0..row_ids_compressed.len()];
let simple_blocks: &[SimpleCompressedPostingBlock<f32>] = &[];
let extended_blocks: &[ExtendedCompressedPostingBlock<f32>] = &[];
let original: CompressedPostingListView<'_, f32> = CompressedPostingListView {
row_ids_compressed: row_ids_slice,
simple_blocks,
extended_blocks,
compressed_block_type: CompressedBlockType::Simple,
quantization_params: None,
row_ids_count: 10,
max_row_id: None,
};
let cloned = original.clone();
// 验证原始和克隆的切片是否指向同一内存位置
assert!(original.row_ids_compressed as *const _ == cloned.row_ids_compressed as *const _);
assert!(original.simple_blocks as *const _ == cloned.simple_blocks as *const _);
assert!(original.extended_blocks as *const _ == cloned.extended_blocks as *const _);
println!("{:?}", row_ids_slice as *const _); // 0x75254c000d10
println!("{:?}", original.row_ids_compressed as *const _); // 0x75254c000d10
println!("{:?}", cloned.row_ids_compressed as *const _); // 0x75254c000d10
}
这段代码会发生一个警告:
1
2
3
4
ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
`#[warn(ambiguous_wide_pointer_comparisons)]` on by defaultrustcClick for full compiler diagnostic
compressed_posting_list_view.rs(248, 17): use `std::ptr::addr_eq` or untyped pointers to only compare their addresses: `std::ptr::addr_eq(`, `, `, `)`
compressed_posting_list_view.rs(248, 17): use explicit `std::ptr::eq` method to compare metadata and addresses: `std::ptr::eq(`, `, `, `)`
这里我们需要了解 Rust 宽指针的概念,https://stackoverflow.com/questions/57754901/what-is-a-fat-pointer
本文由作者按照 CC BY 4.0 进行授权