调整堆栈大小(或其他可动态调整大小的类型)的方法

时间:2014-12-14 03:24:37

标签: data-structures rust

首先,我已经阅读了这个问题:

问题

选择的答案只是告诉提问者使用标准库而不是解释实现,如果我的目标是构建一些东西,这很好。除了我试图了解堆栈的实现,同时遵循为Java (Algorithms by Robert Sedgwick& Kevin Wayne)编写的数据结构教科书,他们通过调整大小来实现堆栈数组(页136)

我正在实现resize方法,结果发现数组的大小需要是一个常量表达式。

  meta:是生锈的数组叫做切片吗?

use std::mem;

struct DynamicStack<T> {
  length: uint,
  internal: Box<[T]>,
}

impl<T> DynamicStack<T> {
  fn new() -> DynamicStack<T> {
    DynamicStack {
      length: 0,
      internal: box [],
    }
  }

  fn resize(&mut self, new_size: uint) {
    let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };

    // ^^ error: expected constant expr for array 
    // length: non-constant path in constant expr

    // code for copying elements from self.internal

    self.internal = temp;
  }
}

为简洁起见,编译器错误就是这个

.../src/lib.rs:51:23: 51:38 error: expected constant expr for array length: non-constant path in constant expr
.../src/lib.rs:51     let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };
                                        ^~~~~~~~~~~~~~~
.../src/lib.rs:51:23: 51:38 error: expected constant expr for array length: non-constant path in constant expr
.../src/lib.rs:51     let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };
                                        ^~~~~~~~~~~~~~~

问题

当然,有一种生锈方法可以在运行时确定阵列的大小(即使它不安全)?你能否解释你的答案中发生了什么?

其他尝试

我认为根据

来实现堆栈可能是可能的
struct DynamicStack<T> {
  length: uint,
  internal: Box<Optional<T>>
}

但我不希望匹配可选值的开销来删除不安全的内存操作,但这仍然无法解决未知数组大小的问题。

我也试过这个(它甚至不编译)

fn resize(&mut self, new_size: uint) {
  let mut temp: Box<[T]> = box [];
  let current_size = self.internal.len();

  for i in range(0, current_size) {
    temp[i] = self.internal[i];
  }
  for i in range(current_size, new_size) {
    temp[i] = unsafe { mem::uninitialized() };
  }

  self.internal = temp;
}

我得到了这个编译器错误

.../src/lib.rs:55:17: 55:21 error: cannot move out of dereference of `&mut`-pointer
.../src/lib.rs:55       temp[i] = self.internal[i];
                                  ^~~~
.../src/lib.rs:71:19: 71:30 error: cannot use `self.length` because it was mutably borrowed
.../src/lib.rs:71       self.resize(self.length * 2);
                                    ^~~~~~~~~~~
.../src/lib.rs:71:7: 71:11 note: borrow of `*self` occurs here
.../src/lib.rs:71       self.resize(self.length * 2);
                        ^~~~
.../src/lib.rs:79:18: 79:22 error: cannot move out of dereference of `&mut`-pointer
.../src/lib.rs:79     let result = self.internal[self.length];
                                   ^~~~
.../src/lib.rs:79:9: 79:15 note: attempting to move value to here
.../src/lib.rs:79     let result = self.internal[self.length];
                          ^~~~~~
.../src/lib.rs:79:9: 79:15 help: to prevent the move, use `ref result` or `ref mut result` to capture value by reference
.../src/lib.rs:79     let result = self.internal[self.length];

我也看过这个,但是自从我做过任何C / C ++之后已经有一段时间了

1 个答案:

答案 0 :(得分:4)

  

当然在Rust中有一种方法可以初始化一个数组,其大小是在运行时确定的吗?

不,Rust数组只能能够使用编译时已知的大小创建。事实上,每个类型和大小的元组构成一个新类型! Rust编译器使用该信息进行优化。

一旦需要在运行时确定一组内容,就必须添加运行时检查以确保Rust的safety guarantees始终有效。例如,您无法访问未初始化的内存(例如,通过离开一组项目的开头或结尾)。

如果你真的想沿着这条路走下去,我希望你不得不用一些直接的内存分配和不安全的代码来解决问题。从本质上讲,您将构建一个较小版本的Vec本身!为此,您可以查看source of Vec

在较高级别,您需要分配大到足以容纳某些类型的N个对象的内存块。然后,您可以使用指针算法提供访问这些元素的方法。添加更多元素时,可以分配更多空间并移动旧值。有许多细微之处可能会或可能不会出现,但听起来你正处于一个有趣的旅程的开始!

修改

当然,您可以选择假装Vec的大部分方法都不存在,只使用与Java数组类似的方法。您仍然需要使用Option来避免未初始化的值。