如何告诉编译器不要对参数求值?

时间:2019-05-25 11:42:01

标签: rust

我想指示Rust编译器在任何情况下都不求值。这是一个示例:

#![allow(dead_code)]

trait CheckTrait {
    fn check(b : bool);
}

struct CheckStructA {}

struct CheckStructB {}

impl CheckTrait for CheckStructA {
    fn check(_b : bool) {
        println!("CheckStructA");
    }
}

impl CheckTrait for CheckStructB {
    // compiler: do not evaluate the argument _b
    fn check(_b : bool) {
    }
}

fn show_stuff_a() -> bool {
    println!("Show stuff A");
    true
}

fn show_stuff_b() -> bool {
    println!("Show stuff B");
    true
}

fn test_a<T : CheckTrait>(_ : T) {
    T::check(show_stuff_a());
}

fn test_b<T : CheckTrait>(_ : T) {
    T::check(show_stuff_b());
}

fn main() {
    test_a(CheckStructA{});
    test_b(CheckStructB{});
 }

这里CheckStructB实际上是CheckStructA的禁用版本。在注释的地方,我希望能够指示编译器不要为_b计算任何表达式可以计算CheckStructB::check,但仍可以为{{1} }。此代码的结果是,它将仍然向控制台输出“ Show Stuff A”,但不会向控制台输出“ Show Stuff B”。

在C#中,可以通过将注释替换为[System.Diagnostics.Conditional(“ DoNotEverTurnThisOn”)]来完成。我不想在宏中定义类型,因为这会破坏智能感知。

我如何在Rust中做到这一点?

1 个答案:

答案 0 :(得分:6)

仅在必要时评估参数称为“懒惰评估”。

在像Haskell这样的语言(默认为“惰性评估”)中,类型bool的参数或变量实际上不会立即表示为bool,而是表示为“ thunk”,包含要调用的函数及其自己的参数(可能是重击)。

在Rust中,由于默认设置是Eager Evaluation,因此您需要以参数类型或有价值的类型显式表示惰性。通常,这不是通过要求T,而是要求FnOnce() -> T来完成的。

因此,您将check重写为:

fn check<F: FnOnce() -> bool>(condition: F);

然后,由实现决定是否评估F,如果没有评估,则什么也不执行。

注意:如果您不希望使用泛型check,则可以将Box<FnOnce() -> bool>作为参数;但是,它将需要堆分配...就像在Haskell中一样。


让我们看看一些代码! Playground link

trait CheckTrait {
    fn check<F: FnOnce() -> bool>(b: F);
}

struct CheckStructA {}

struct CheckStructB {}

impl CheckTrait for CheckStructA {
    fn check<F: FnOnce() -> bool>(b: F) {
        b();
        println!("CheckStructA");
    }
}

impl CheckTrait for CheckStructB {
    fn check<F: FnOnce() -> bool>(_b: F) {
        println!("CheckStructB");
    }
}

fn show_stuff_a() -> bool {
    println!("Show stuff A");
    true
}

fn show_stuff_b() -> bool {
    println!("Show stuff B");
    true
}

fn test_a<T : CheckTrait>(_ : T) {
    T::check(|| show_stuff_a());
}

fn test_b<T : CheckTrait>(_ : T) {
    T::check(|| show_stuff_b());
}

fn main() {
    test_a(CheckStructA{});
    test_b(CheckStructB{});
}