Rust 是否检测重复的闭包(例如,在循环中定义的闭包)?

Does Rust detects duplicated closures (eg. ones defined in loop)?

提问人:Siiir 提问时间:2/20/2023 最后编辑:Siiir 更新时间:2/23/2023 访问量:56

问:

当我需要调用许多可失败的函数时,我有时会将它们关闭。 然后我他们并捕获任何特殊变体(其他语言中的异常机制)。?

以下是我对 https://www.codewars.com/kata/5a090c4e697598d0b9000004/train/rust 的解决方案。

use std::collections::VecDeque;

fn solve(nums: &[i32]) -> Vec<i32> {
    let mut sorted = VecDeque::from_iter(nums.iter().copied());
    sorted.make_contiguous().sort();

    let mut rearranged = vec![];
    while let Some(()) =
        (||->Option<()>{
            rearranged.push(sorted.pop_back()?);
            rearranged.push(sorted.pop_front()?);
            Some(())
        })()
    {}
    rearranged
}

效果很好,很干净,但我想知道, “Rust 是否在每次循环迭代中都会生成一个闭包实例?(编辑:我添加了实例这个词) 如果是这样,它是否检测到生成的闭包是第一个闭包的“只是重复” 并优化重复?while

如上所述,如果对在循环中定义闭包的情况进行一些理论上的考虑,我将不胜感激。编译器会进行哪些优化以避免数据重复?

loops rust closures 编译器优化

评论


答:

2赞 Peter Hall 2/21/2023 #1

最简单的检查方法是查看生成的程序集,当然使用 .--release

您的代码:

solve:
    pushq   %rbp
    pushq   %r15
    pushq   %r14
    pushq   %r13
    pushq   %r12
    pushq   %rbx
    subq    $200, %rsp
    movq    %rdi, %r8
    testq   %rdx, %rdx
    je  .LBB6_6
    movq    %rdx, %rbx
    movq    %r8, 128(%rsp)
    xorl    %ebp, %ebp
    movq    %rdx, %rax
    shrq    $61, %rax
    sete    %al
    jne .LBB6_128
    movq    %rsi, %r14
    leaq    (,%rbx,4), %rdi
    movb    %al, %bpl
    shlq    $2, %rbp
    movq    %rdi, 104(%rsp)
    movq    %rbp, %rsi
    callq   *__rust_alloc@GOTPCREL(%rip)
    testq   %rax, %rax
    je  .LBB6_129
    movq    %rbx, 40(%rsp)
    leaq    (%r14,%rbx,4), %r12
    addq    $-4, %r12
    movq    %r12, %rbp
    subq    %r14, %rbp
    movq    %rbp, %rbx
    shrq    $2, %rbx
    leaq    4(%rbp), %rdx
    andq    $-4, %rdx
    movq    %rax, (%rsp)
    movq    %rax, %rdi
    movq    %r14, %rsi
    callq   *memcpy@GOTPCREL(%rip)
    leaq    1(%rbx), %rax
    movq    %rax, 16(%rsp)
    cmpq    $80, %rbp
    jae .LBB6_7
    movl    $1, %r15d
    cmpq    %r14, %r12
    movq    (%rsp), %r12
    je  .LBB6_106
    movq    16(%rsp), %rax
    leaq    (%r12,%rax,4), %r8
    addq    $-4, %r8
    leaq    (%r12,%rbx,4), %rcx
    addq    $4, %rcx
    movq    $-2, %rbp
    jmp .LBB6_97

在变量(playground)中定义闭包:

solve:
    pushq   %rbp
    pushq   %r15
    pushq   %r14
    pushq   %r13
    pushq   %r12
    pushq   %rbx
    subq    $200, %rsp
    movq    %rdi, %r8
    testq   %rdx, %rdx
    je  .LBB6_6
    movq    %rdx, %rbx
    movq    %r8, 128(%rsp)
    xorl    %ebp, %ebp
    movq    %rdx, %rax
    shrq    $61, %rax
    sete    %al
    jne .LBB6_128
    movq    %rsi, %r14
    leaq    (,%rbx,4), %rdi
    movb    %al, %bpl
    shlq    $2, %rbp
    movq    %rdi, 104(%rsp)
    movq    %rbp, %rsi
    callq   *__rust_alloc@GOTPCREL(%rip)
    testq   %rax, %rax
    je  .LBB6_129
    movq    %rbx, 40(%rsp)
    leaq    (%r14,%rbx,4), %r12
    addq    $-4, %r12
    movq    %r12, %rbp
    subq    %r14, %rbp
    movq    %rbp, %rbx
    shrq    $2, %rbx
    leaq    4(%rbp), %rdx
    andq    $-4, %rdx
    movq    %rax, (%rsp)
    movq    %rax, %rdi
    movq    %r14, %rsi
    callq   *memcpy@GOTPCREL(%rip)
    leaq    1(%rbx), %rax
    movq    %rax, 16(%rsp)
    cmpq    $80, %rbp
    jae .LBB6_7
    movl    $1, %r15d
    cmpq    %r14, %r12
    movq    (%rsp), %r12
    je  .LBB6_106
    movq    16(%rsp), %rax
    leaq    (%r12,%rax,4), %r8
    addq    $-4, %r8
    leaq    (%r12,%rbx,4), %rcx
    addq    $4, %rcx
    movq    $-2, %rbp
    jmp .LBB6_97    

它们是相同的。

评论

0赞 Siiir 2/23/2023
谢谢你的比较。对我来说,这意味着我不需要显式地“在变量中定义闭包”来获得这种优化。我理解得很清楚吗?