Generics 在模板化代码时,锈报告不能移出取消引用

Generics 在模板化代码时,锈报告不能移出取消引用,generics,rust,Generics,Rust,Rust中的以下代码编译良好: pub fn insertion_sort(data : &mut [int]){ let n = data.len(); for j in range(1, n){ let key = data[j]; // we insert data[j] into the sorted sequence //data[0...j-1] let mut i = j -1; while data[i] > ke

Rust中的以下代码编译良好:

pub fn insertion_sort(data : &mut [int]){
  let n  = data.len();
  for j in range(1, n){
    let key = data[j];
    // we insert data[j] into the sorted sequence 
    //data[0...j-1]
    let mut i = j -1;
    while data[i] > key{
        data[i + 1]  = data[i];
        if i == 0{
            break;
        }
        i -= 1;
    }
    data[i] = key;
  }
}
但现在,我将介绍以下泛型:

pub fn insertion_sort<T : Ord>(data : &mut [T]){
  let n  = data.len();
  for j in range(1, n){
    let key = data[j];
    // we insert data[j] into the sorted sequence 
    //data[0...j-1]
    let mut i = j -1;
    while data[i] > key{
        data[i + 1]  = data[i];
        if i == 0{
            break;
        }
        i -= 1;
    }
    data[i] = key;
  }
}

通过值传递时,将复制实现
Copy
特征的类型(例如int)。对于所有其他类型,按值传递意味着移动

添加一个
Copy
绑定,它将像以前一样工作,但仅限于
Copy
类型


或者,使用
克隆
绑定并显式克隆元素,而不是移动它们。

是的,您需要特别小心,因为在您使用的原始代码段中,
int
,它可以隐式复制(实现trait),在第二部分中,您仅将泛型参数与
Ord
绑定一起使用。默认情况下,Rust中的值是移动的,而不是复制的,这确实会对值的处理带来一些限制。如果您编写
而不是只编写
,则可以观察到这一点-您的代码将再次开始编译。然而,这不是一个合适的通用解决方案,因为许多类型都不是
Copy

首先,你应该阅读其中的解释,除其他外,所有权和借用,核心生锈的概念是绝对需要理解的,以便有效地使用生锈。您看到的错误是这些概念的结果。基本上,如果您有一个到某个数据结构的引用,您就不能将任何内容移出这个结构。Slice是对连续数据块的引用;因为您没有在
t
上指定
Copy
绑定,Rust无法从切片复制值,也无法移动这些值,因为禁止从引用后面移动。所以它发出了一个错误

这样的行为听起来很有限制性,有时的确如此。很多用其他语言(主要是C语言)自然完成的事情不能直接用Rust完成。作为回报,生锈提供了巨大的安全保障。然而,有时确实需要编写一些本身安全的东西,但这种安全性对编译器来说并不明显。当您实现基本的数据结构和算法(如排序)时,通常会发生这种情况。当然,最终的工具是
不安全的
块,但在这种情况下,您不需要它们。Rust在模块中提供了几个非常有用的函数,尤其是和。但是,特别是对于切片,有一个直接在切片上调用的方法。它以给定的指数交换元素。如果您根据交换操作重新格式化插入排序,您将能够编写适用于所有
Ord
类型的完全通用代码,即使它们不可复制。我强烈建议您尝试这样做,因为这将帮助您了解如何编写低级别的Rust程序

另一方面,如果您事先知道只使用基本类型,如
int
,则可以安全地将
Copy
绑定到
T
,并保持代码原样。或者,您可以使用更通用的
Clone
bind,但在从切片中提取值时,需要调用
Clone()
方法:

pub fn insertion_sort<T: Ord+Clone>(data: &mut [T]) {
  let n = data.len();
  for j in range(1, n) {
    let key = data[j].clone();
    // we insert data[j] into the sorted sequence 
    //data[0...j-1]
    let mut i = j -1;
    while data[i] > key {
        data[i + 1] = data[i].clone();
        if i == 0 {
            break;
        }
        i -= 1;
    }
    data[i] = key;
  }
}
pub fn插入\u排序(数据:&mut[T]){
设n=data.len();
对于范围(1,n)内的j{
让key=data[j].clone();
//我们将数据[j]插入到排序序列中
//数据[0…j-1]
设muti=j-1;
而数据[i]>键{
数据[i+1]=数据[i]。克隆();
如果i==0{
打破
}
i-=1;
}
数据[i]=密钥;
}
}

我正在努力找到一种使用mem::swap实现相同功能的方法。例如,我不能这样做:mem::swap(&mut data[I+1],&mut data[I]);因为我自然不能借两倍的可变利率。是的,你说得对。我认为您需要使用该方法来可变地访问多个点中的切片。不幸的是,这是更高层次的安全代价;低性能的算法和数据结构必须使用变通方法编写,并且
不安全
。对不起,我对
swap()
的理解有些错误。我的意思是,虽然有这样的函数,但是切片另外提供了一种方法,专门在两个索引处交换元素,它也被称为。您应该使用它而不是
mem::swap()
函数。感谢Vladimir,我已经编辑了这个问题,提出了一个适用于T:Ord并使用slice.swap方法的版本。它编译并运行。这里有一个小问题。T:Ord+Copy版本会更快还是swap()版本会更快?比如说内置类型?两者都不会明显快于另一种。事实上,片上只有一个薄薄的包装器,它通过一个临时变量复制字节。Rust严重依赖于LLVM优化,如内联,因此这段特定代码可能会在任何情况下内联并优化。
pub fn insertion_sort<T: Ord+Clone>(data: &mut [T]) {
  let n = data.len();
  for j in range(1, n) {
    let key = data[j].clone();
    // we insert data[j] into the sorted sequence 
    //data[0...j-1]
    let mut i = j -1;
    while data[i] > key {
        data[i + 1] = data[i].clone();
        if i == 0 {
            break;
        }
        i -= 1;
    }
    data[i] = key;
  }
}