Rod*_*igo 2 lambda closures vector rust
这是我试图实现的 C++ 等价物:
std::vector<std::function<int(int)>> funcs;
funcs.emplace_back([](int n) -> int { return n + 1; });
int result = funcs[0](33);
Run Code Online (Sandbox Code Playgroud)
如何在 Rust 中编写上面的代码?
如果您不打算将函数移动到特定的任何地方,您可以让类型推断在代码块中为您完成工作,并且非常严格地定义您的闭包,就像它是一个普通变量(实际上,它是 - 它实现了Fn或FnMut):
let my_lambda = |n| n+1;
println!("{}", my_lambda(33));
Run Code Online (Sandbox Code Playgroud)
如果您打算将此 lambda 移出堆栈,则需要将其装箱:
let my_lambda: Box<dyn Fn(u32) -> u32> = Box::new(|n| n + 1);
println!("{}", my_lambda(33));
Run Code Online (Sandbox Code Playgroud)
这里的原则保持不变,唯一真正的区别是 lambda 现在在堆上。
将它们存储在Vecthen 中变得相对简单,因为现在我们已经证明它们是“正常”类型。没有什么可以阻止您创建闭包向量,但是您需要将它们装箱(Vec要求每个元素都是Sized,并且无法通过签名来定位两个不同的闭包)并且它们需要具有相同的签名:
let my_vector: Vec<Box<dyn Fn(u16) -> u16>> = vec![
Box::new(|i| i + 1),
Box::new(|i| i - 1),
];
println!("{}", my_vector[0](33))
Run Code Online (Sandbox Code Playgroud)
如果它们具有不同的签名,您将需要编写自己的结构来包含它们并通过签名对它们进行存储,这不是一项简单的任务。
基准案例:
C++:
let my_lambda = |n| n+1;
println!("{}", my_lambda(33));
Run Code Online (Sandbox Code Playgroud)锈:
fn main() {
let mut lambdas:Vec<Box<Fn(u32) -> u32>> = vec![];
for i in 0..10000000 {
lambdas.push(Box::new(|i| i+1));
lambdas[i](3);
}
}
Run Code Online (Sandbox Code Playgroud)编译选项:
-O3 --std=c++0x--release结果:
C++ 峰值堆大小:
let my_lambda: Box<dyn Fn(u32) -> u32> = Box::new(|n| n + 1);
println!("{}", my_lambda(33));
Run Code Online (Sandbox Code Playgroud)Rust 峰值堆大小:
let my_vector: Vec<Box<dyn Fn(u16) -> u16>> = vec![
Box::new(|i| i + 1),
Box::new(|i| i - 1),
];
println!("{}", my_vector[0](33))
Run Code Online (Sandbox Code Playgroud)结论:
std::function包装器是堆分配的。它包含的原始 lambda 本身是堆栈分配的,这种行为与 Rust 一致