文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
5.2.2 返回值
当闭包作为返回值时,依旧要用到特征。以告知接收方获取了哪种闭包,该如何使用。
fn test() -> impl FnOnce(i32) -> i32 { |x: i32| x + 1 // 是不是闭包,或者是不是 move, } // 对 FnOnce 没有影响。 fn main() { let inc = test(); // 受影响的是 inc,必须遵守 FnOnce 约束。 inc(1); // inc(1); // ^^^ value used here after move }
fn test() -> impl FnMut(i32) -> i32 { |x: i32| x + 1 } fn main() { let mut inc = test(); // FnMut,必须 mut !!! inc(1); inc(1); }
如闭包引用局部变量,须转移所有权,确保能安全释放。
- 复制环境变量。
- 或强制转移(move)。
fn test() -> impl FnMut(char) { let mut s = String::from("abc"); |c| { s.push(c); } // FnMut,也就是说闭包生命周期超过 s。 } // 要么把 s 复制,要么用 move 转移所有权。 fn main() { let mut c = test(); c('d'); c('e'); }
error[E0373]: closure may outlive the current function, but it borrows `s`, which is owned by the current function | 3 | |c| { s.push(c); } | ^^^ - `s` is borrowed here | | | may outlive borrowed value `s` | help: to force the closure to take ownership of `s` (and any other referenced variables), use the `move` keyword | 3 | move |c| { s.push(c); } | ^^^^^^^^
实现
和普通所有权转移类似的操作。
fn test() -> impl Fn() { let s = [0x11i64, 0x22i64, 0x33i64, 0x44i64, 0x55i64]; move || { println!("{:?}", s); } } fn main() { let c = test(); c(); }
(gdb) b 3 (gdb) b 10 (gdb) r (gdb) disass Dump of assembler code for function demo::test: 0x00005555555591f0 <+0>: sub rsp,0x38 ; main 提供的返回值内存地址。 0x00005555555591f4 <+4>: mov rax,rdi ; 环境变量 s,栈分配。 0x00005555555591f7 <+7>: mov QWORD PTR [rsp+0x10],0x11 0x0000555555559200 <+16>: mov QWORD PTR [rsp+0x18],0x22 0x0000555555559209 <+25>: mov QWORD PTR [rsp+0x20],0x33 0x0000555555559212 <+34>: mov QWORD PTR [rsp+0x28],0x44 0x000055555555921b <+43>: mov QWORD PTR [rsp+0x30],0x55 ; 复制环境变量。 ; void* memcpy( void *dest, const void *src, size_t count ); ; rax rdi rsi rdx ; 返回 main 提供的内存地址。 => 0x0000555555559224 <+52>: lea rcx,[rsp+0x10] 0x0000555555559229 <+57>: mov rsi,rcx 0x000055555555922c <+60>: mov edx,0x28 0x0000555555559231 <+65>: mov QWORD PTR [rsp+0x8],rax 0x0000555555559236 <+70>: call 0x555555559060 <memcpy@plt> 0x000055555555923b <+75>: mov rax,QWORD PTR [rsp+0x8] 0x0000555555559240 <+80>: add rsp,0x38 0x0000555555559244 <+84>: ret End of assembler dump.
(gdb) c Breakpoint 2, demo::main main.rs:10 (gdb) ptype c # 查看闭包结构。 type = struct demo::test::closure-0 ( [i64; 5], ) (gdb) p c # 查看闭包内容。 $1 = demo::test::closure-0 ( [17, 34, 51, 68, 85] ) (gdb) x/5xg &c # 内存地址和值。 0x7fffffffe198: 0x0000000000000011 0x0000000000000022 0x7fffffffe1a8: 0x0000000000000033 0x0000000000000044 0x7fffffffe1b8: 0x0000000000000055 (gdb) p/x $rsp # 复制到 main 栈帧。 $2 = 0x7fffffffe190 (gdb) disass Dump of assembler code for function demo::main: 0x0000555555559250 <+0>: sub rsp,0x38 ; 由 main 提供内存,用于保存 test 返回的闭包对象。 0x0000555555559254 <+4>: lea rdi,[rsp+0x8] 0x0000555555559259 <+9>: call 0x5555555591f0 <demo::test> ; 将闭包传递给匿名函数。 => 0x000055555555925e <+14>: lea rdi,[rsp+0x8] 0x0000555555559263 <+19>: call 0x555555559820 <demo::test::{{closure}}> 0x0000555555559268 <+24>: add rsp,0x38 0x000055555555926c <+28>: ret End of assembler dump.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论