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

问题描述 投票:0回答:1

首先,我读过这个问题:

问题

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

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

meta:Rust 中的数组称为切片吗?

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() };
                                        ^~~~~~~~~~~~~~~

问题

Rust 中肯定有一种方法可以初始化一个数组,其大小在运行时确定(即使它不安全)?您能否也解释一下您的答案中发生了什么?

其他尝试

我认为可能可以根据

来实现堆栈
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++ 了

data-structures rust
1个回答
4
投票

Rust 中肯定有一种方法可以在运行时确定其大小来初始化数组吗?

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

一旦您需要在运行时确定一组事情,您就必须添加运行时检查以确保 Rust 的“安全保证”始终有效。例如,您无法访问未初始化的内存(例如离开一组项目的开头或结尾)。 如果您真的想走这条路,我希望您将不得不亲自尝试一些直接的内存分配和不安全的代码。本质上,您将构建

Vec

本身的较小版本!为此,您可以查看

Vec的来源
在较高层次上,您将需要分配足够大的内存块来容纳某种类型的 N 个对象。然后,您可以使用底层的指针算术来提供访问这些元素的方法。添加更多元素时,您可以分配更多空间并移动旧值。有很多微妙的事情可能会出现,也可能不会出现,但听起来你正处于一个有趣的旅程的开始!

编辑

当然,你可以选择假装

Vec

的大多数方法都不存在,而只使用与Java数组类似的方法。不过,您仍然需要使用

Option
来避免未初始化的值。
    

© www.soinside.com 2019 - 2024. All rights reserved.