【问题标题】:How to correctly represent a stack based language in Rust?如何在 Rust 中正确表示基于堆栈的语言?
【发布时间】:2018-10-18 19:35:54
【问题描述】:

我正在尝试模仿Parsing a simple imperative language (Haskell) 的第 3 部分。特别是,我正在考虑使用基于堆栈的语言而不是命令式语言,并且我正在尝试使用惯用的 Rust 代码来表示数据。

假设您想要制作一个小的(非常小的stack based language,它有一些基本的算术运算,没有用户定义的函数,并且可以处理十进制数和整数。比如:

   1 2 +
-> Stack contains: 3

发生了什么事?从左到右读取,将 1 和 2 压入堆栈,+ 会压出 12,然后将 3 (= 1 + 2) 压入堆栈。

我的想法是考虑3 需要解析的“原语”类型。你有整数、十进制数和函数。此外,十进制和整数都是“名词”,而函数是“动词”。所以当执行一个程序时,我的想法是你可以通过扩展 Result<T, E> 枚举的想法在 Rust 中表示这些想法。我想出了以下方案:

enum Noun {
    Integer(i64),
    Decimal(f64)
}

enum Primitive<T> {
    Noun(T),
    Verb(Fn(Vec<Noun>) -> Noun),
}

// Not really important, just giving a main so it can be ran
fn main() {
    println!("Hello, world!");
}

换句话说,原语要么是Noun,要么是Verb,而Noun要么是整数,要么是浮点数。

但是,这会导致:

error[E0277]: the trait bound `std::ops::Fn(std::vec::Vec<Noun>) -> Noun + 'static: std::marker::Sized` is not satisfied
 --> main.rs:8:10
  |
8 |     Verb(Fn(Vec<Noun>) -> Noun),
  |          ^^^^^^^^^^^^^^^^^^^^^^ `std::ops::Fn(std::vec::Vec<Noun>) -> Noun + 'static` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `std::ops::Fn(std::vec::Vec<Noun>) -> Noun + 'static`
  = note: only the last field of a struct may have a dynamically sized type

error: aborting due to previous error(s)

在 Rust 中执行此操作的标准方法是什么?

【问题讨论】:

    标签: rust


    【解决方案1】:

    Fn(Vec&lt;Noun&gt;) -&gt; Noun 类型描述了一个 trait 对象,它是实现此 trait 的任何类型的占位符。由于 trait 可以通过普通函数或捕获额外变量的闭包来实现,编译器无法知道为这样的对象分配多少空间。特征对象是“动态大小的”,因此不能存在于堆栈中。

    解决错误消息的一种方法是存储在堆中:

    enum Primitive<T> {
        Noun(T),
        Verb(Box<dyn Fn(Vec<Noun>) -> Noun>),
    }
    

    dyn 关键字明确表明我们正在处理一个特征对象,并且对该对象的方法调用是动态分派的。它在当前的 Rust 中是可选的,但建议在新代码中使 trait 对象更加明显。

    另一种方法是使用普通函数指针而不是特征对象:

    enum Primitive<T> {
        Noun(T),
        Verb(fn(Vec<Noun>) -> Noun),
    }
    

    函数指针只能指向普通函数或不捕获任何变量的闭包,因此它是静态大小的,因此可以存储在堆栈中。

    就个人而言,我可能会实现一个名为 Function 或类似名称的自定义特征,并使用

    enum Primitive<T> {
        Noun(T),
        Verb(Box<dyn Function>),
    }
    

    自定义 trait 将为您提供更大的灵活性,将元数据和附加方法附加到 trait 对象,例如检索函数将使用的输入数量的方法。

    【讨论】:

      猜你喜欢
      • 2017-02-20
      • 1970-01-01
      • 2012-07-20
      • 2020-07-09
      • 2017-12-05
      • 2016-08-22
      • 2021-05-31
      • 2012-11-08
      • 1970-01-01
      相关资源
      最近更新 更多