Как мне сказать компилятору не оценивать аргумент? - PullRequest
3 голосов
/ 25 мая 2019

Я бы хотел дать указание компилятору 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, но по-прежнему оценивать выражение, которое вычислит _b для CheckStructA::check.Следствием этого кода является то, что он по-прежнему выводит «Show Stuff A» на консоль, но не выводит «Show Stuff B» на консоль.

В C # это можно сделать, заменив комментарий на [System.Diagnostics.Conditional ("DoNotEverTurnThisOn")].Я не хочу определять типы внутри макроса, потому что это нарушает intellisense.

Как мне это сделать в Rust?

1 Ответ

6 голосов
/ 25 мая 2019

Только оценка аргументов по мере необходимости называется Lazy Evaluation.

В таких языках, как Haskell, для которых Lazy Evaluation является значением по умолчанию, аргумент или переменная типа bool фактически не представляется как boolнемедленно, вместо этого он представляется как «thunk», который содержит функцию для вызова и свои собственные аргументы (потенциально thunks).

В Rust, поскольку Eager Evaluation является значением по умолчанию, вам необходимо явно представить лень вТип аргумента или ценный.Обычно это делается путем запроса не T, а FnOnce() -> T.

Поэтому вы должны переписать check как:

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

Тогда, реализация должна либо оценить F, либо нет, и если она не оценена, ничего не будет выполнено.

Примечание: если вы не хотите универсальный check, вы можете взять Box<FnOnce() -> bool> в качестве аргумента;однако для этого потребуется выделение кучи ... как в Haskell.


Давайте посмотрим код! Ссылка на игровую площадку

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{});
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...