Rust 克隆研究综述
在《铁 rust 》中,Clone
的特征是,
专为任意复制而设计:类型T
的Clone
实现可以执行创建新T
所需的任意复杂操作.
这意味着它可能会创建一个深拷贝或浅拷贝.然而,对于铁 rust String
或Vec<String>
,它可以进行深度复制:
fn main() {
// Clone and then mutate a string
let mut s: String = String::from("Initial value");
let mut s_clone: String = s.clone();
s_clone = String::from("New value");
println!("s is: {s}\ns_clone is: {s_clone}");
// Clone and then mutate a vector of strings
let mut s_vec: Vec<String> = vec!["a".to_string(), "b".to_string()];
let mut s_vec_clone: Vec<String> = s_vec.clone();
s_vec_clone[0] = "c".to_string();
println!("s_vec is: {:?}\ns_clone is: {:?}", s_vec, s_vec_clone);
}
这将返回:
s is: Initial value
s_clone is: New value
s_vec is: ["a", "b"]
s_clone is: ["c", "b"]
我会预料到这种行为,因为按引用与按值是关键的differences between a String
and &str
之一.
Cloning Strings
in extendr
用于Clone
特性状态的extendr_api::wrapper::strings::Strings
实现的docs,
返回值的副本.
由于它没有指定深或浅,我们可能会期望Strings
的行为与String
或String
的向量相同.这也将与Rcpp
人中的clone()
人保持一致.
然而,您的示例表明它不是深度副本,因为修改副本也会修改原始副本.
Strings
是extendr
的主力的包装器,即extendr_api::robj::Robj
,它本身就是一个
S表达式指针(SEXP)的包装器.
正如提醒R Internals所说的,
R用户认为变量或对象是绑定到某个值的符号.该值可以被认为是SEXP
(指针),或者它指向的 struct 是SEXPREC
Clone
个性状代表Robj
calls Robj::from_sexp(self.get())
,而这又是calls:
/// Access to a raw SEXP pointer can cause undefined behaviour and is not thread safe.
unsafe fn get(&self) -> SEXP;
即它返回一个指针,而不是对象本身.duplicate()
方法的docs证实了这一点:
对此对象进行深度复制.请注意,Clone()只添加了一个引用.
但是,您会注意到duplicate()
返回一个Robj
类型的对象.这对我来说似乎有点奇怪,因为我希望Strings
对象的副本返回Strings
对象.但是,使用Strings::try_from()
将Robj
强制返回Strings
很简单,请记住,此方法返回Result<Strings>
,因此我们需要将其解包.
rust_source(code = '
#[extendr]
fn strings_elt(x: Strings) -> Strings {
let mut y = Strings::try_from(x.duplicate()).unwrap();
y.set_elt(0, "AAA".into());
rprintln!("x is {:?} and y is {:?}", x, y);
y
}
')
s <- c("aaa", NA, "bbb")
s1 <- strings_elt(s)
s1 # "AAA" NA "bbb"
s # "aaa" NA "bbb"
我们现在可以看到,修改副本不再更改原始副本.