When I need to call many failable functions, I sometimes put them into closure.
Then I ?
them and catch any special variant (exception mechanism in other languages).
The following is my solution to 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
}
Works fine and is clean, but I wonder,
“Does Rust produce a closure instance on every while
loop iteration”? (EDIT: I added the word instance)
If so, does it detect that produced closures are “just duplicates” of the first one
and optimizes duplication away?
I would be grateful for some theoretical consideration of cases when closure is defined inside the loop, like above. What optimizations compiler does to avoid duplication of data?
The easiest way to check is to have a look at the generated assembly, of course using --release
.
Your code:
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
Defining the closure in a variable (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
They're identical.