试图取消引用`&`-pointer

And*_*rea 3 algorithm pointers rust

我正在尝试在Rust中编写一个naif实现kmeans用于学习目的.其中一个步骤如下:我有一组积分xs和另一个积分centroids.我想xs基于质心中最近的邻居对其进行分组.也就是说,如果两个点具有共同的最近邻居,则它们属于同一组.

例如在Scala中,这看起来像

xs groupBy { x => closest(x, centroids) } values 
Run Code Online (Sandbox Code Playgroud)

我没有groupBy在标准库中找到方法,我试着写下如下(假设Pointclosest定义):

fn clusters(xs: & Vec<Point>, centroids: & Vec<Point>) -> Vec<Vec<Point>> {
  let mut groups: TreeMap<Point, Vec<Point>> = TreeMap::new();

  // for x in xs.iter() {
  //   let y = closest(*x, centroids);
  //   match groups.find(&y) {
  //     Some(mut val) => val.push(*x),
  //     None => {
  //       groups.insert(y, vec![*x]);
  //     },
  //   }
  // }

  let result: Vec<Vec<Point>> = groups.values().map(|x| *x).collect();
  result
}
Run Code Online (Sandbox Code Playgroud)

我已经评论了中心部分,因为我已经有问题创建TreeMap<Point, Vec<Point>>并将其值返回为Vec<Vec<Point>>.valuesTreeMap上有一个方法,它返回一个类型的迭代器Map<...>.我试过了:

  • 直接返回迭代器,但Rust抱怨说我必须添加一个生命周期说明符,我不确定使用哪一个
  • 将它收集到一个Vec.问题是迭代器的元素实际上是指针Vec<Point>,所以我必须做类似的事情let result: Vec<& Vec<Point>> = groups.values().collect();.同样,Rust不会让我回复那些指针,因为它们太活了
  • 取消引用所有这些指针,如上所述.我认为这是正确的方法,但Rust告诉我error: cannot move out of dereference of &-pointer

返回该地图值的正确方法是什么?

另外,如果我取消对中心部分的拒绝,Rust会阻止我这样做,groups.insert(y, vec![*x]);因为groups在模式匹配中本地借用了它作为不可变引用.我该如何解决这个问题?

PEP*_*EPP 5

你的第一个问题是values()返回一个对象,该对象向TreeMap提供不可变的投影,但是你试图在地图调用中将数据移出它.

两种可能的解决方案是:1)您创建向量的副本.然而,这是昂贵的操作.

let result: Vec<Vec<Point>> = groups.values().map(|x| x.clone()).collect();
Run Code Online (Sandbox Code Playgroud)

2)使用消耗树图的into_iter()方法,您可以自由地移出数据.

let result: Vec<Vec<Point>> = groups.into_iter().map(|(p, v)| v).collect();
Run Code Online (Sandbox Code Playgroud)

然后,评论代码中存在两个问题.

首先,您必须获得对已找到项目的可变引用,因此您必须调用find_mut()而不是find().

其次,在None分支中,您尝试插入已经借用的树形图(通过find()/ find_mut()调用的结果).Rust不会让你.目前,唯一的选择是在匹配块之后推迟插入:

  let should_insert = match groups.find_mut(&y) {
      Some(mut val) => {
        val.push(*x);
        false
      }
      None => {
          true
      },
  };
  if should_insert {
      groups.insert(y, vec![*x]);
  }
Run Code Online (Sandbox Code Playgroud)

编辑:在较新版本的Rust中有更好的方法:

use std::collections::btree_map::Entry;
match groups.entry(&y) {
    Entry::Occupied(mut view) => { val.get_mut().push(*x); }
    Entry::Vaccant(view) => { view.insert(vec![*x]); }
};
Run Code Online (Sandbox Code Playgroud)