如何从函数中返回一个已拥有的数组?

11

我是一个 Rust 初学者,尝试通过使用它来理解这门语言。在尝试从函数返回一个数组时遇到了一些问题:

struct Widget {
  thingies: ~[int]
}

impl Widget {
    fn new() -> Widget {
        Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
    }

    fn somethings(&self) -> ~[int] {
        self.thingies
    }
}

fn main() {
   let widget = Widget::new();
   let wotsits = widget.somethings();
}

当然,这会导致编译失败并出现以下错误:

pointers.rs:11:8: 11:21 error: cannot move out of dereference of & pointer
pointers.rs:11         self.thingies

如果这段代码看起来有些混乱,我只是试图从一个实现的结构体中提取一个数组。所借用的指针并不重要,这只是我尝试存储数据的方式。

有什么方法可以正确地提取我的数组吗?

顺便说一下,我正在使用Rust 0.8


~ 是一个独特的指针,只能有一个(指向相同的值)。它们不能像原始的 C 指针一样被复制(别名)。试图创建另一个值(返回值)会将该值从原始指针中移出,这将使 thingies 和整个 self 未定义,这当然是不允许的。你可能想要返回一个借用指针,而不是拿走 self.thingies。 - hamstergene
[T] 被称为 向量,而不是 数组。人们通常区分两者的区别在于数组是静态大小的,而向量可以增长或缩小。 - Chris Morgan
3个回答

15
你的代码无法编译的原因是,独占式指针 ~ 只能有一个所有者。编译器正在防止你编写错误倾向的代码。你可以决定返回 thingies 的副本、thingies 的引用或 thingies 的切片(它是对向量数据或其一部分的引用)。 复制解决方案
struct Widget {
  thingies: ~[int]
}

impl Widget {
    fn new() -> Widget {
        Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
    }

    fn somethings(&self) -> ~[int] {
        self.thingies.clone()
    }
}

参考解决方案

struct Widget {
  thingies: ~[int]
}

impl Widget {
    fn new() -> Widget {
        Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
    }

    fn somethings<'a>(&'a self) -> &'a~[int] {
        &self.thingies
    }
}

分片解决方案

struct Widget {
  thingies: ~[int]
}

impl Widget {
    fn new() -> Widget {
        Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
    }

    fn somethings<'a>(&'a self) -> &'a[int] {
        self.thingies.as_slice()
    }
}

为了理解引用和切片解决方案,您需要了解 'a 的含义: 它表示生命周期,&'a 是一种告诉编译器引用必须不超过它所引用的对象的方式,这种情况下是 Widget。
这些解决方案也有一些限制: 您不能修改当前正在引用的对象,因为这样做会导致引用无效的可能性。
当然,如果您返回一个可变引用,可以修改物品。带有生命周期的可变引用将被写成 &'a mut T
struct Widget {
  thingies: ~[int]
}

impl Widget {
    fn new() -> Widget {
        Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
    }

    fn somethings<'a>(&'a mut self) -> &'a mut ~[int] {
        &mut self.thingies
    }
}

注意 我认为在Rust 0.8中,你需要写&'self而不是&'a,因为当时自定义名称的生命周期还不被支持。我也在0.9中编写了这个。

编辑:删除了冗余的生命周期声明。


除非您需要在结构体内部使用借用指针,否则无需在结构体上放置生命周期注释。这不是这种情况。您可以只对“somethings”方法进行参数化:fn somethings<'a><(&'a mut self) -> &'a mut ~[int] ... - Vladimir Matveev
关于0.8的评论,我发现代码在使用&'a时可以正常工作,我不需要将其更改为&'self。 - Greg Malcolm

8

=== 编辑 ===

在 Rust 1 稳定版中,~[T] 变成了 Vec<T>,但是(语法除外),相同的问题仍然存在,因为 Vec 仍然有一个唯一的所有者。简而言之,somethings 只有对自身的引用,(通过引用)它无法成为 thingies 的所有者。Rust 的所有权模型对该语言非常重要,因此建议查看关于 所有权借用 的优秀官方文档以获取更多信息。

在这里查看 Rust 1 版本的 Playground 链接:https://play.rust-lang.org/?gist=50ec1acdc684e53fd5f9&version=stable

=== 结束编辑 ===

在Rust中,self后面的.会自动解引用self,因此这是错误提到的&指针的解引用
现在,物体的所有权是您无法移动出解引用的部分:
   let widget = Widget::new(); // widget owns the unique pointer to self
   let wotsits = widget.somethings(); // if this worked, ownership of 
                                      // unique pointer to thingies would be
                                      // moved to wotsits

你可以借用物品的引用:
fn somethings<'a>(&'a self) -> &'a~[int] {
    &self.thingies
}

或者明确地返回 thingies 的一个副本
fn somethings(&self) -> ~[int] {
    self.thingies.clone()
}

很抱歉再次打扰你,但有更多的人正在尝试更新1.0之前的问题。让我们进行一个更大的群聊吧。 - Shepmaster

2

正如其他答案所解释的那样,您不能移动借用指针。但是您可以通过值或拥有的指针传递self,然后您就可以返回拥有的向量:

struct Widget {
    thingies: ~[int]
}

impl Widget {
    fn somethings(self) -> ~[int] {
        self.thingies
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接