我在内存中有两个相邻的切片.我知道它们是相邻的,因为我刚刚从一个有split_at个的切片创建了它们.我想将它们连接在一起,再次获得覆盖整个范围的切片.我有什么办法可以安全地做到这一点吗?理想情况下,某些函数会获取多个切片,查看它们是否彼此相邻,并在可能的情况下将它们合并在一起.

fn main() {
    let original_slice: &[u8] = &[1, 2, 3, 4];
    
    let (left, right) = original_slice.split_at(2);
    
    let rejoined_slice = todo!("take left and right and return an Option or similar")
    
    assert_eq!(original_slice, rejoined_slice);
    assert_eq!(original_slice.as_ptr(), rejoined_slice.as_ptr());
}

Playground

接下来我将使用zerocopy个 crate 执行一些零拷贝解析.有时,我会得到多个类型相同的切片,我知道它们彼此相邻(毕竟,我只是解析它们、判断它们的对齐等),将它们融合在一起会很有用.

不是this question的副本:我不想以一个新的Vec结束,我想在不复制的情况下将已经相邻的切片融合在一起.

推荐答案

这实际上是一个颇具争议性的话题:目前还没有决定这种能力是否应该在all实现,而目前的共识(根据我对讨论的解读)似乎倾向于支持这种能力.摘自std::ptr年中的文档:

种源

This section is non-normative and is part of the 100 experiment.

指针不是简单的"整数"或"地址".例如,说在释放之后使用显然是未定义的行为是没有争议的,即使您"幸运地"并且在读/写之前重新分配释放的内存(事实上,这是最坏的情况,如果这种情况没有发生,UFA就不会那么担心了!).为了使这种说法合理化,指针需要以某种方式不仅仅是它们的地址:它们必须有出处.

...

缩小起源是不可撤销的:即使你"知道"有更大的分配,你也不能派生出一个具有更大起源的指针.同样,你也不能把两个相邻的种源重新组合成一个(即fn merge(&[T], &[T]) -> &[T]).


如果最终决定允许扩大来源,您可以通过一些指针操作实现这一点:

/// SAFETY: Both parameters must refer to the same allocated object.
unsafe fn rejoin<'a, T>(a: &'a [T], b: &'a [T]) -> Option<&'a [T]> {
    if a.as_ptr().add(a.len()) == b.as_ptr() {
        Some(std::slice::from_raw_parts(a.as_ptr(), a.len() + b.len()))
    } else {
        None
    }
}

但请注意,我仍然将函数设置为unsafe,并留下了一条注释,记录了这一点.从理论上讲,两个切片可以是相邻的,同时又是独立的对象.例如,let a = [1, 2];let b = [3, 4];可以合理地作为堆栈上的连续变量,但将它们作为单个片访问将是未定义的行为.因此,该函数应为unsafe,并且调用方必须确保它们来自相同的源对象.

Rust相关问答推荐

如何在 struct 中填充缓冲区并同时显示它?

在HashMap中插入Vacant条目的可变借位问题

什么样的 struct 可以避免使用RefCell?

从Rust调用C++虚拟方法即使在成功执行之后也会引发Access违规错误

为什么&;mut buf[0..buf.len()]会触发一个可变/不可变的borrow 错误?

Rust从关联函数启动线程

我应该如何表达具有生命周期参数的类型的总排序,同时允许与不同生命周期进行比较?

为什么带有生命周期指定的方法不能被调用两次?

Rust 中的 Option as_ref 和 as_deref 有什么不同

如果不满足条件,如何在 Rust 中引发错误

rust tokio::spawn 在 mutexguard 之后等待

如何将参数传递给Rust 的线程?

Rust 函数指针似乎被borrow 判断器视为有状态的

使用 `clap` 在 Rust CLI 工具中设置布尔标志

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

第 7.4 章片段中如何定义 `thread_rng`

当我不满足特征界限时会发生什么?

实现不消费的迭代器

有没有办法使用 NASM 语法进行内联汇编?

在 Rust 中有条件地导入?