【发布时间】:2022-01-24 19:52:37
【问题描述】:
在 Rust 中,如果我想在多个上下文中对一个 &str 进行只读访问而不复制 实际 底层数据,我认为我只使用切片是否正确?
示例
let original_string = "here's a string";
let slice = &original_string[0..3];
或者需要Rc<str> 之类的东西吗?
【问题讨论】:
在 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::take 或std::mem::replace。
由至少一个共享引用 &T 借用的任何数据必须在该引用的生命周期内只读,但具有内部可变性的容器内的数据除外,例如 Cell<T>、RefCell<T>、Mutex<T>和AtomicU32。
通常,使用引用的最大限制是它们的生命周期必须短于数据所有者的生命周期。在某些情况下,这可能会使代码难以或不可能纯粹用引用和生命周期来表达。像Rc<T> 和Arc<T> 这样的引用计数指针可以提供帮助,因为它们通常类似于共享引用&T,除了不是从其他位置借用数据,而是将数据移动到Rc/@987654340 @ 然后数据所有权在该Rc/Arc 的所有克隆之间共享,从而限制了对引用生命周期的需求,但运行时成本很小。
【讨论】:
只读访问一个 &str
你是对的,代码没有复制字符串,&str基本上包括2部分,一个指针和一个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()
}
}
【讨论】: