如何在Rust中将两个切片合并为覆盖中间区域的连续切片?
在Rust中合并两个切片为覆盖两者及中间内容的切片
如果你需要将两个来自同一原始数据的切片,合并成一个覆盖它们本身及中间所有内容的切片,核心是获取两个切片在原始数据中的起始和结束位置,再取最小起始索引与最大结束索引来生成新切片。
针对字符串切片(&str)的实现
以你的示例代码为例,我们可以通过指针偏移计算切片在原始字符串中的索引:
fn main() { let text = "the dog and cat run"; let dog = &text[4..7]; let cat = &text[12..15]; // 计算两个切片在原字符串中的起始/结束字节索引 let dog_start = (dog.as_ptr() as usize) - (text.as_ptr() as usize); let dog_end = dog_start + dog.len(); let cat_start = (cat.as_ptr() as usize) - (text.as_ptr() as usize); let cat_end = cat_start + cat.len(); // 取最小起始位置和最大结束位置 let start = dog_start.min(cat_start); let end = dog_end.max(cat_end); let dog_and_cat = &text[start..end]; println!("{:?}", dog); // "dog" println!("{:?}", cat); // "cat" println!("{:?}", dog_and_cat); // "dog and cat" }
通用切片(&[T])的实现
对于任意类型的切片,原理类似,需要结合元素的内存大小计算索引:
use std::mem; fn merge_slices<T>(original: &[T], a: &[T], b: &[T]) -> &[T] { // 计算切片在原始数组中的字节偏移 let a_start = (a.as_ptr() as usize) - (original.as_ptr() as usize); let a_end = a_start + a.len() * mem::size_of::<T>(); let b_start = (b.as_ptr() as usize) - (original.as_ptr() as usize); let b_end = b_start + b.len() * mem::size_of::<T>(); // 确定合并后的字节范围 let start_byte = a_start.min(b_start); let end_byte = a_end.max(b_end); // 转换为元素索引 let start_idx = start_byte / mem::size_of::<T>(); let end_idx = end_byte / mem::size_of::<T>(); &original[start_idx..end_idx] } fn main() { let arr = [1,2,3,4,5,6,7,8]; let slice1 = &arr[1..3]; // [2, 3] let slice2 = &arr[5..7]; // [6, 7] let merged = merge_slices(&arr, slice1, slice2); println!("{:?}", merged); // [2, 3, 4, 5, 6, 7] }
注意事项
- 必须保证两个切片都来自同一个原始数据(字符串/数组),否则指针偏移计算会导致未定义行为。
- 处理UTF-8字符串时,只要原始切片是从合法的UTF-8边界切割的,生成的新切片也会是合法的UTF-8,因为我们是基于字节偏移计算,且保留了合法的边界。
内容的提问来源于stack exchange,提问作者Erik Bongers
相关产品推荐
相关产品推荐

