rust_interview icon indicating copy to clipboard operation
rust_interview copied to clipboard

[Advance] 闭包捕获变量顺序

Open ZhangHanDong opened this issue 8 years ago • 20 comments
trafficstars

let c = move || {
        {
            let y_ref = &y;
        }
        x; y; z;
    };

假如x、y、z都是外部变量,那么上面闭包示例中,是先捕获y呢,还是先捕获z ?析构顺序是什么样的?

ZhangHanDong avatar Nov 18 '17 11:11 ZhangHanDong

这个是按栈的顺序吗? 即 z,y,x -> x,y,z

biluohc avatar Nov 24 '17 14:11 biluohc

捕获顺序为 y, x, z, 单纯是按闭包内使用的顺序

析构为 x, y, z, 因为第五行 consume 的顺序是这样的

iovxw avatar Nov 24 '17 16:11 iovxw

@iovxw 析构也是y,x,z

ZhangHanDong avatar Nov 25 '17 02:11 ZhangHanDong

@biluohc 你说的是let声明绑定的析构顺序,这里是闭包,略有不同

ZhangHanDong avatar Nov 25 '17 02:11 ZhangHanDong

看来每个issue需要配上play比较好

ZhangHanDong avatar Nov 25 '17 02:11 ZhangHanDong

总感觉莫名其妙,可以写个结构加闭包验证下

biluohc avatar Nov 25 '17 02:11 biluohc

https://play.rust-lang.org/?gist=1233af65c31bfb32603d07c10b009ce2&version=stable

ZhangHanDong avatar Nov 25 '17 02:11 ZhangHanDong

你来看看我这个, 呵 https://play.rust-lang.org/?gist=2d780efb162f4e9b5d396f61207c1e9c&version=stable

biluohc avatar Nov 25 '17 02:11 biluohc

catch不知道怎么验证, MIR里是这样的, 大概是y,x,z, 即使用顺序.

fn main() -> () {
    let mut _0: ();                      // return pointer
    scope 1 {
        let _1: PrintDrop;               // "y" in scope 1 at src/main.rs:9:9: 9:10
        scope 3 {
            let _2: PrintDrop;           // "x" in scope 3 at src/main.rs:10:9: 10:10
            scope 5 {
                let _3: PrintDrop;       // "z" in scope 5 at src/main.rs:11:9: 11:10
                scope 7 {
                    let _4: [closure@src/main.rs:12:19: 15:6 y:PrintDrop, x:PrintDrop, z:PrintDrop]; // "closure" in scope 7 at src/main.rs:12:9: 12:16
                }
                scope 8 {
                }
            }
            scope 6 {
            }
        }
        scope 4 {
        }
    }
    scope 2 {
    }
    let mut _5: PrintDrop;
    let mut _6: PrintDrop;
    let mut _7: PrintDrop;
    let mut _8: ();
    let mut _9: [closure@src/main.rs:12:19: 15:6 y:PrintDrop, x:PrintDrop, z:PrintDrop];
    let mut _10: ();

biluohc avatar Nov 25 '17 02:11 biluohc

@iovxw 谢啦.

biluohc avatar Nov 25 '17 02:11 biluohc

@biluohc y,x,z那是捕获顺序。 你这个例子,调用了闭包,是另外一道题了。

ZhangHanDong avatar Nov 25 '17 03:11 ZhangHanDong

那你说说闭包使用与否对析构有什么影响? 因为没有闭包内部的作用域使用, 就按catch顺序drop?

biluohc avatar Nov 25 '17 03:11 biluohc

@biluohc 闭包调用确实是有影响的。目前按结果来看是这样。

ZhangHanDong avatar Nov 25 '17 03:11 ZhangHanDong

我去, 还能像css盒子模型那样重合..

闭包调用换成; 就和那个没有使用闭包的一样了. 所以你说的这个坑和这个题没有关系吧.

biluohc avatar Nov 25 '17 04:11 biluohc

@biluohc 汗! 那个说法错了,我改了。 不是那个坑的问题。

ZhangHanDong avatar Nov 25 '17 04:11 ZhangHanDong

@biluohc 你可以看看加上闭包调用和不加闭包调用的MIR。

其实闭包没有调用之前,在闭包的MIR里打的drop标记顺序和使用顺序是一致的。 但是这个drop标记是在运行时才执行的,也就是闭包执行才能按这个drop标记析构。 但是如果闭包没有调用,这个drop标记就没用。只能按离开main函数作用域时候的捕获顺序来析构了。

比较闭包调用和没有闭包调用两种情况的MIR,你会发现:

_14 = const std::ops::FnOnce::call_once(_15, _16) -> [return: bb5, unwind: bb9]; // scope 7 at

只有真正调用,闭包里的drop标记才会起作用。

ZhangHanDong avatar Nov 25 '17 04:11 ZhangHanDong

@biluohc

不过经过你这么一改,加闭包调用和不加闭包调用,可以作为这道题的两种情况去考察了。:D

ZhangHanDong avatar Nov 25 '17 04:11 ZhangHanDong

嗯, , 不过你不用删回复吧, 即使有错误, 以免后来者读不通.

biluohc avatar Nov 25 '17 04:11 biluohc

@biluohc 还是删了吧,我怕看的人被我带到歧路里去

ZhangHanDong avatar Nov 25 '17 07:11 ZhangHanDong

https://play.rust-lang.org/?gist=d080a6eb2ce59586b8c03a0c7933e23f&version=nightly

可否得出结论是析构按照comsume顺序?

huangjj27 avatar Feb 06 '18 16:02 huangjj27