Если вы не планируете перемещать функцию в каком-либо конкретном месте, вы можете позволить выводу типа сделать работу за вас внутри блока кода и буквально определить ваше закрытие, как будто оно является нормальной переменной (на практике это - этореализует либо Fn
, либо FnMut
):
let my_lambda = |n| n+1;
println!("{}", my_lambda(33));
Playground
Если вы собираетесь вывести эту лямбду из стека, вам нужно будетэто:
let my_lambda: Box<dyn Fn(u32) -> u32> = Box::new(|n| n + 1);
println!("{}", my_lambda(33));
Детская площадка
Принцип здесь тот же, единственное реальное отличие состоит в том, что лямбда теперь в куче.
Хранение их в Vec
затем становится относительно простым, поскольку к настоящему моменту мы доказали, что это «нормальные» типы.Ничто не мешает вам создать вектор замыканий, но вам нужно их пометить (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))
Если они имеют разрозненные подписи, вам нужно написать свою собственную структуру, которая будет содержать их, и поместить их в подпись, и это не простая задача.
Тестовый корпус:
C ++:
#include <vector>
#include <iostream>
#include <functional>
int main(int argc, char **argv) {
std::vector<std::function<int(int)>> funcs;
for (int i = 0; i < 10000000; i++) {
funcs.push_back([&] (int n) { return n + 1; });
int result = funcs[i](33);
}
}
Rust:
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);
}
}
Варианты компиляции:
- G ++:
-O3 --std=c++0x
- Груз:
--release
Результаты:
C ++ пиковый размер кучи:
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
68 383,911,899 268,512,208 268,508,160 4,048 0
69 555,878,425 805,387,160 805,379,072 8,088 0
70 765,593,697 805,387,160 805,379,072 8,088 0
Размер пиковой кучи ржавчины:
--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
46 210,486,321 268,440,920 268,436,765 4,155 0
47 210,486,371 268,440,976 268,436,805 4,171 0
48 210,486,496 268,441,064 268,436,885 4,179 0
Выводы:
Оболочки
- C ++
std::function
размещаются в куче.Сама необработанная лямбда, которую она содержит, распределяется по стеку, и это поведение соответствует Rust - Rust лучше при оптимизации памяти, потребляя треть размера кучи C ++
- Rust такжебыстрее с точки зрения сырого времени