【问题标题】:What is the idiomatic Rust way to copy/clone a vector in a parameterized function?在参数化函数中复制/克隆向量的惯用 Rust 方法是什么?
【发布时间】:2014-02-17 15:26:15
【问题描述】:

我正在尝试编写一个参数化函数,该函数采用不可变向量,克隆或复制它,对新向量执行某些操作(例如随机播放)并将其作为新拥有的向量返回。如何做到这一点,最惯用的方法是什么?

尝试 #1

pub fn shuffle<T>(vec: &mut [T]) {
    // ... contents removed: it shuffles the vector in place
    // ... so needs a mutable vector
}

pub fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut newvec = vec.clone();
    shuffle(&mut newvec);
    return newvec.to_owned();
}

失败:

error[E0596]: cannot borrow immutable borrowed content as mutable
 --> src/main.rs:8:13
  |
8 |     shuffle(&mut newvec);
  |             ^^^^^^^^^^^ cannot borrow as mutable

即使我声明 newvec 是可变的。我不明白为什么。

尝试 #2

pub fn shuffle_owned<T: Clone>(mut vec: Vec<T>) -> Vec<T> {
    shuffle(&mut vec);
    return vec;
}

虽然编译,但它并没有做我想要的。您传递给shuffle_owned 的向量被移动 到函数中,经过洗牌,然后将其所有权转移回调用者(通过返回值)。所以原来的向量被修改了。

我想知道如何传入一个不会发生变异的向量,但是将值克隆到一个新的装箱向量中并在完成时返回——就像你在函数式编程语言中所做的那样具有不可变的数据(例如 Clojure)。

【问题讨论】:

  • to _owned 克隆[T] 的每个元素,因此需要T 来实现克隆(&lt;T: Clone&gt;)
  • 是的,这解释了错误。谢谢。
  • 我已经更新了我的答案,因为您的建议修复了第一个错误,但我仍然没有弄清楚如何实现我的总体目标。

标签: rust


【解决方案1】:

您的尝试#1 几乎是正确的,您只需将to_owned() 移动到第一行:

fn shuffle<T>(vec: &mut [T]) {
    // ...
}

fn shuffle_create_new<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut newvec = vec.to_vec();
    shuffle(&mut newvec);
    newvec
}

发生这种情况是因为在切片上调用clone() 将返回一个切片(即&amp;[T]),并且您不能从&amp;[T] 转到&amp;mut [T],因为您不能选择引用的可变性(借用指针)。但是,当您调用 to_owned() 时,您将获得 Vec&lt;T&gt; 的新实例,您可以将其放入可变变量中以获取可变向量。

从 Rust 1.0 开始,ToOwned 特征中的 slice::to_vec 或 to_owned() 方法可用于从 &amp;[T] 创建 Vec&lt;T&gt;。

现在还有几种方法可以从Vec&lt;T&gt; 获取&amp;mut [T]:切片表示法(&amp;mut vec[..])、deref 转换(&amp;mut *vec)或直接方法调用(vec.as_mut_slice(),尽管这是一种已弃用):

【讨论】:

【解决方案2】:

这可能就是你想要的:

pub fn copy_shuffle<T: Clone>(vec: &Vec<T>) -> Vec<T> {
    let mut vec = vec.clone();
    shuffle(&mut vec);
    vec
}

或

pub fn copy_shuffle<T: Clone>(vec: &[T]) -> Vec<T> {
    let mut vec = vec.to_vec();
    shuffle(&mut vec);
    vec
}

【讨论】:

  • 你是对的,这也有效 - 感谢您提供有关此类构造的提示!您的答案与@Vladimir 的答案之间的区别在于,当您调用它时,您必须使用地址:copy_shuffle(&amp;myvec) 与shuffle_create_new(myvec)。我猜 Vladimir 的版本是更惯用的 Rust,但我不太确定。我会接受他的回答,但如果我的点赞数有误,请让社区告诉我。
  • @quux00,你说得对。在&amp;~[T] 的情况下,您有两个间接级别(我不确定,也许LLVM 可以在执行代码中对其进行优化,但它们仍然存在于语义级别),&amp;[T] 或~[T] 有只有一个。但是,有时这是唯一可行的方法,例如,在实现像 Add&lt;X, Y&gt; 这样的通用特征时,至少在将未指定大小的类型(如 [T])添加到语言之前。
猜你喜欢
  • 2021-01-18
  • 1970-01-01
  • 2011-09-24
  • 2022-08-18
  • 2021-06-12
  • 2023-01-15
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
相关资源
最近更新 更多