对字符串进行切片是否会复制基础数据



在Rust中,如果我想在多个上下文中只读访问一个&str,而不复制实际的底层数据,那么我认为我只使用切片是正确的吗?

示例

let original_string = "here's a string";
let slice = &original_string[0..3];

或者需要Rc<str>这样的东西吗?

任何引用类型&T&mut T(包括像&str&[T]这样的切片类型(都只会借用数据,使用时不会隐式复制或移动数据。

您可以通过用*解除对实现Copy的类型的引用,或者通过调用clone方法,从引用显式复制到实现Clone的类型。您还可以显式地移出可变引用,方法是用不同的值替换它,例如用std::mem::takestd::mem::replace

至少一个共享引用&T借用的任何数据在该引用的生存期内都必须是只读的,但具有内部可变性的容器内的数据除外,如Cell<T>RefCell<T>Mutex<T>AtomicU32

通常,使用引用的最大限制是它们的生存期必须短于数据所有者的生存期。在某些情况下,这可能会使代码难以或不可能纯粹用引用和生存期来表达。像Rc<T>Arc<T>这样的引用计数指针会有所帮助,因为它们的作用通常类似于共享引用&T,只是数据不是从其他位置借用数据,而是移动到Rc/Arc中,然后在该Rc/Arc的所有克隆之间共享数据所有权,从而减少了对引用寿命的需要,但运行时成本很小。

只读访问一个&str

你是对的,代码没有复制字符串,&str基本上包括两个部分,一个指针和一个len,因此

let original_string = "here's a string";
let slice = &original_string[0..3];
println!("{:?}", original_string.as_ptr());
println!("{:?}", original_string.len());
println!("{:?}", slice.as_ptr());
println!("{:?}", slice.len());

输出看起来像

0x1074d4ee3
15
0x1074d4ee3
3

对字符串进行切片不会复制。这意味着你必须保持原始字符串至少和切片一样长。(Frxstrem的回答更好地解释了这一点。(

Rc<str>对您没有帮助,因为它必须是同一字符串或切片上的Rc,也就是说,您不能创建子切片,而是用它计算同一基字符串上的引用。如果您确实需要这样的东西,您必须在原始字符串上存储Rc,并用它存储当前切片范围,例如:

#[derive(Clone)]
struct SharedString {
string: Rc<str>,
slice: Range<usize>,
}
impl Deref for SharedString {
type Target = str;
fn deref(&self) -> &str {
self.string.get(self.slice.clone()).unwrap()
}
}

游乐场

最新更新