文章

在 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 进行授权