例如,我想将R字符串s <- c("aaa", NA, "bbb")更改为s1 <- c("AAA", NA, "bbb"),并保留原始的s.在下面的代码中,我可以进行更改并将新字符串分配给s1.第s章也变了我在Rust代码中复制了一个.clone()的s.第s章为什么会变?

library(rextendr)

rust_source(code = '
#[extendr]
fn strings_elt(x: Strings) -> Strings {
    let mut y = x.clone();
    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", also changed

推荐答案

Rust 克隆研究综述

在《铁 rust 》中,Clone的特征是,

专为任意复制而设计:类型TClone实现可以执行创建新T所需的任意复杂操作.

这意味着它可能会创建一个深拷贝或浅拷贝.然而,对于铁 rust StringVec<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的行为与StringString的向量相同.这也将与Rcpp人中的clone()人保持一致.

然而,您的示例表明它不是深度副本,因为修改副本也会修改原始副本.

Stringsextendr的主力的包装器,即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"

我们现在可以看到,修改副本不再更改原始副本.

R相关问答推荐

以R表示的gglikert地块调整总数

如何在ggplot 2 geom_segment图表中将UTC转换为EET?

如何从其他前面列中减go 特定列的平均值?

terra nearest()仅为所有`to_id`列返回NA

pickerInput用于显示一条或多条geom_hline,这些线在图中具有不同 colored颜色

如何在R中添加截止点到ROC曲线图?

ggplot的轴标签保存在officer中时被剪切

IMF IFS数据以R表示

从BRM预测价值

移除仪表板Quarto中顶盖和车身之间的白色区域

如何从R ggplot图片中获取SVG字符串?

DEN扩展包中的RECT树形图出现异常行为

如何基于两个条件从一列中提取行

根据1个变量绘制 colored颜色 发散的 map ,由另一个变量绘制饱和度,ggplot2不工作

如何根据数据帧中的值从该数据帧中提取值?

悬崖三角洲超大型群数计算导致整数溢出

判断函数未加载R中的库

在ggploy中创建GeV分布时出错

Data.table::Shift type=允许扩展数据(&Q;LAG&Q;)

如何用不同长度的向量填充列表?