gpt4 book ai didi

rust - 以特征作为参数的 Rust 闭包

转载 作者:行者123 更新时间:2023-12-03 11:27:41 25 4
gpt4 key购买 nike

我希望我的函数采用闭包作为参数,它采用 PartialOrd(或任何其他特征,这只是一个示例)作为参数,我希望能够调用它在我的函数中实现 PartialOrd 的任何类型的闭包。类似这样的事情:

fn my_func(cmp: fn(impl PartialOrd, impl PartialOrd) -> bool) {
cmp(3, 5);
}

但这当然不起作用,因为 impl Trait 在闭包签名中无效。 (我不明白为什么,但我猜它还没有实现。)所以我尝试了这样的事情:

fn my_func<T: PartialOrd>(cmp: fn(T, T) -> bool) {
cmp(3, 5);
}

这也不能编译,因为(我猜)T 是由调用者决定的,我只是传递 i32 并且它可能与调用者不同旨在调用。

那么,我该怎么做呢?我的主要目的是做这样的事情:

fn my_func(cmp: fn(impl PartialOrd, impl PartialOrd) -> bool) {
if some_condition {
cmp(type1_instance, type1_instance_2);
} else {
cmp(type2_instance, type2_instance_2);
}
}

type1type2 都实现了 PartialEq

为了让它更具体,我正在使用 chrono 库并想写这样的东西:

fn compare_dates(d1: DateTime, d2: DateTime, cmp: fn(impl PartialOrd, impl PartialOrd) -> bool) -> bool {
if some_condition {
cmp(d1, d2)
} else {
cmp(d1.date(), d2.date())
}
}

compare_dates(
Utc.date(2000 10, 11).and_hour(0,0,0),
Utc.date(2000 10, 12).and_hour(0,0,0),
PartialOrd::lt)

注意:DateTime::date() 不返回 DateTime,它返回不同的 Date 类型。

最佳答案

拥有单个 cmp 的问题在于,虽然它在函数声明中可能是通用的,但在函数被调用时它会变得特殊化。因此它不能同时用于 DateTimeDate(假设您想避免涉及 Any 的更复杂的事情。)

您可以通过使用两个 cmp 参数来解决这个问题。但是,您仍然可以对实际的 cmp 函数进行单一定义。

// chrono = "0.4.19"
use chrono::{Date, DateTime, TimeZone, Utc};

fn compare_dates<F, G>(
d1: DateTime<Utc>,
d2: DateTime<Utc>,
cmp_date_times: F,
cmp_dates: G,
) -> bool
where
F: FnOnce(&DateTime<Utc>, &DateTime<Utc>) -> bool,
G: FnOnce(&Date<Utc>, &Date<Utc>) -> bool,
{
let some_condition = ...;
if some_condition {
cmp_date_times(&d1, &d2)
} else {
cmp_dates(&d1.date(), &d2.date())
}
}

现在您可以定义一个通用的 cmp 函数并将其用于两者。

fn cmp<T: PartialOrd>(lhs: &T, rhs: &T) -> bool {
lhs < rhs
}

compare_dates(
Utc.ymd(2000, 10, 11).and_hms(0, 0, 0),
Utc.ymd(2000, 10, 12).and_hms(0, 0, 0),
cmp,
cmp,
// or
// cmp::<DateTime<Utc>>,
// cmp::<Date<Utc>>,
);

您也可以只传递 PartialOrd::lt

compare_dates(
Utc.ymd(2000, 10, 11).and_hms(0, 0, 0),
Utc.ymd(2000, 10, 12).and_hms(0, 0, 0),
PartialOrd::lt,
PartialOrd::lt,
// or
// <DateTime<Utc> as PartialOrd>::lt,
// <Date<Utc> as PartialOrd>::lt,
// or
// DateTime::<Utc>::lt,
// Date::<Utc>::lt,
);

如果你想避免重复参数,那么你也可以定义一个 compare_dates! 宏。

macro_rules! compare_dates {
($d1:expr, $d2:expr, $cmp:expr $(,)?) => {
compare_dates($d1, $d2, $cmp, $cmp)
};
}

然后你可以这样调用:

compare_dates!(
Utc.ymd(2000, 10, 11).and_hms(0, 0, 0),
Utc.ymd(2000, 10, 12).and_hms(0, 0, 0),
PartialOrd::lt,
);

compare_dates!(
Utc.ymd(2000, 10, 11).and_hms(0, 0, 0),
Utc.ymd(2000, 10, 12).and_hms(0, 0, 0),
cmp,
);

关于rust - 以特征作为参数的 Rust 闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65470374/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com