gpt4 book ai didi

rust - 存储闭包以供重用的惯用方法?

转载 作者:行者123 更新时间:2023-11-29 08:03:54 25 4
gpt4 key购买 nike

在 Rust 中传递闭包非常简单,但是当存储闭包以供重用时,有多种解决方案(使用通用函数类型、引用闭包或 box,是否具有 'static 生命周期的 box? ...)。

虽然我已经使用不同类型的盒装类型多次混淆了这个问题,但阅读了类似的问答,甚至可以冒险猜测回答这个问题。我不知道如何处理这个问题,即使是简单/明显的情况,也不知道一个好的起点是什么。

为了使问题更具体,什么是使此示例存储函数以供重用的好方法,使用构建器模式来存储稍后调用的闭包。

// This example looks a bit long but its really very simple.

// * This example is most of the way to implementing the builder pattern,
// it ust runs the code immediately instead of storing input
// to run on `build()`.
// * Changes should only be needed where the comment `stored closures:`
// has been written.
// * I've attempted to make this example as generic as possible,
// but not _so_ simple that the answer wont apply to real-world use (hopefully!).

struct MyActions {
num: i32,
times: i32,

// stored closures: should be stored here.
// update_fn: Option<Fn(...)>,
// twiddle_fn: Option<Fn(...)>,
}

impl MyActions {
pub fn new(num: i32) -> Self {
return MyActions {
num: num,
times: 1,
}
}

pub fn build(self) -> i32 {
// stored closures:
// should run both actions if they're defined and return the result.
return self.num;
}

pub fn num_times(mut self, times: i32) -> Self {
self.times = times;
self
}

pub fn num_update<F>(mut self, func: F) -> Self
where
F: Fn(i32) -> i32
{
// stored closures: run immediately for now
for _ in 0..self.times {
self.num = func(self.num);
}
self
}

pub fn num_twiddle<F>(mut self, func: F) -> Self
where
F: Fn(i32) -> i32
{
// stored closures: run immediately for now
for _ in 0..self.times {
self.num = func(self.num);
}
self
}
}

// no changes needed here
fn main() {
let act = MyActions::new(133);
let num_other: i32 = 4;

// builder pattern (currently executes immediately).
let result = act
.num_times(8)
.num_update(|x| x * 2 + num_other)
.num_twiddle(|x| (((x / 2) - 1) ^ (x + 1)) ^ num_other)
.build();

// Lets say we would want this example to work,
// where 'times' is set after defining both functions.
/*
let result = act
.num_update(|x| x * 2 + num_other)
.num_twiddle(|x| (((x / 2) - 1) ^ (x + 1)) ^ num_other)
.num_times(8) // <-- order changed here
.build();
*/

println!("done: {}", result);
}

最佳答案

对此的惯用解决方案是将闭包装箱。虽然装箱一个闭包并稍后调用它会产生分配开销和动态调度开销,但在大多数情况下它可以忽略不计,并且 MyAction 类型仍然可以通过友好的错误消息轻松使用。

或者,不同的函数可以是 MyAction 结构的通用字段,它存储闭包而不是间接的。这在某些情况下可以产生巨大的加速,但由于更复杂的错误消息和无法自由移动 MyAction 对象,这种类型的可用性会降低。

如果盒装版本在分析中明显显示速度较慢,那么您可以转向通用版本。否则,我建议继续使用易于使用的盒装版本。

box with 'static lifetime or not?

同样,为简单起见,您可以使用 'static 生命周期,但是您的 MyAction 结构只能存储不借用其环境的闭包。如果您在 MyAction 结构上使用生命周期并将其转发给闭包,您将能够以通用参数为代价借用您的环境,这可能再次导致 MyAction 结构更难正确使用。

关于rust - 存储闭包以供重用的惯用方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41738049/

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