切片字符串会复制底层数据吗?

Does slicing a string copy the underlying data?

在 Rust 中,如果我想跨多个上下文对一个 &str 进行只读访问而不复制 实际 底层数据,我认为我只是使用切片?

例子

let original_string = "here's a string";

let slice = &original_string[0..3];

或者是否需要 Rc<str> 之类的东西?

任何引用类型&T&mut T(包括切片类型&str&[T])只会借用数据,而不会隐式复制或移动数据用过。

您可以通过使用 * 取消引用来显式地从对实现 Copy 的类型的引用进行复制,或者通过调用 [=17] 从对实现 Clone 的类型的引用进行显式复制=] 方法。您还可以通过将其替换为不同的值来显式移出可变引用,例如 std::mem::takestd::mem::replace.

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

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

read-only access to one &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()
    }
}

Playground