是否可以查询闭包的堆栈空间?

时间:2016-10-29 09:04:28

标签: rust

fn test<T>(t: T) {
    println!("size of: {}", std::mem::size_of::<T>());
}
fn main() {
    let f = || {
        let i1: i32 = 0;
        let i2: i32 = 0;
        let i3: i32 = 0;
        i1 + i2 + i3
    };
    test(f) // prints "size of: 0"
}

非移动闭包似乎总是打印尺寸为0,可能是因为它只是内联。

移动闭包随着它捕获的每个变量变大,但我想知道是否有可能查询闭包所需的堆栈空间?

更新

我想创建像Coroutine<F>这样的东西。我需要知道F的大小才能执行它。我目前为每个协程分配1mb这太多了。所以我想知道是否有可能确定我需要分配的实际大小。

1 个答案:

答案 0 :(得分:3)

我误解了这个问题,所以下面的文字并没有真正回答OP的问题!

,您可以衡量一个闭包的大小。有时候尺寸有点混乱。让我们测试各种闭包:

let constant = || 27;
let no_capture = |x: i32| 27 + x;

let a = vec![3];
let immut_capture = || a[0] + 27;
let immut_capture_arg = |x: i32| a[0] + x;

let mut b = vec![3];
let mut c = vec![3];
let mut_capture = || { b[0] += 27; b[0] };
let mut_capture_arg = |x: i32| { c[0] += x; c[0] };

let mut d = vec![3];
let mut e = vec![3];
let move_capture = move || { d[0] += 27; d.into_boxed_slice() };
let move_capture_arg = move |x: i32| { e[0] += x; e.into_boxed_slice() };

当我使用std::mem::size_of_val打印尺码时(大致相当于您手写的test()功能),我得到以下结果:

constant -> 0
no_capture -> 0
immut_capture -> 8
immut_capture_arg -> 8
mut_capture -> 8
mut_capture_arg -> 8
move_capture -> 24
move_capture_arg -> 24

您可以使用this code on playground自行尝试。

那么结果如何呢?

闭包是一种通过引用或值来保存其环境的类型。对大小数据的可变和不可变引用具有相同的大小,即size_of::<usize>(),通常为8.这解释了通过引用捕获外部变量的闭包的大小。

另一方面,移动关闭,通过价值捕获他们的环境,这意味着他们必须将环境保存在自己内部。因此,它们的大小等于size_of::<Vec<_>>()毫不奇怪。

大小为0的闭包怎么样?由于它们没有捕获任何环境,因此它们也可以是普通的fn函数。我猜Rust会把它们变成fn - 函数。事实上,如果我们尝试打印fn项的大小(不是函数指针!),就像这样:

fn foo(x: i32) -> i32 { x +  27 }
println!("{}", std::mem::size_of_val(&foo));

...我们得到0!