Только оценка аргументов по мере необходимости называется 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{});
}