Search code examples
ruststring-interpolation

Which string interpolation method is faster in Rust?


I'm new to Rust and I wonder if any "string-interpolation method" is faster.

let var = "World";
println!("Hello {}", var);
println!("Hello {var}");
format!("{argument}", argument = "test");

Is there even any observable difference?

Since these macros are converted into Rust source code at compile-time, whereby each argument interacts with a formatter, it probably gets optimized away, right?

I wonder about positional parameters and named parameters in particular.


Solution

  • "Hello {}", var, "Hello {var}" and "Hello {argument}", argument = var will compile to the exact same bytecode.

    Note that this is not just an optimization, this is guaranteed to be done at compile time because all three generate the same Arguments object that gets passed on to the the internal print implementation.

    pub fn foo(var: u32){
        println!("Hello {}", var);
    }
    
    pub fn bar(var: u32){
        println!("Hello {var}");
    }
    
    pub fn baz(var: u32){
        println!("Hello {argument}", argument = var);
    }
    
    example::foo:
            sub     rsp, 72
            mov     dword ptr [rsp + 4], edi
            lea     rax, [rsp + 4]
            mov     qword ptr [rsp + 8], rax
            mov     rax, qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt@GOTPCREL]
            mov     qword ptr [rsp + 16], rax
            lea     rax, [rip + .Lanon.460b7f3ee3193f887017359a1e30dfa7.2]
            mov     qword ptr [rsp + 24], rax
            mov     qword ptr [rsp + 32], 2
            mov     qword ptr [rsp + 56], 0
            lea     rax, [rsp + 8]
            mov     qword ptr [rsp + 40], rax
            mov     qword ptr [rsp + 48], 1
            lea     rdi, [rsp + 24]
            call    qword ptr [rip + std::io::stdio::_print@GOTPCREL]
            add     rsp, 72
            ret
    
    example::bar:
            sub     rsp, 72
            mov     dword ptr [rsp + 4], edi
            lea     rax, [rsp + 4]
            mov     qword ptr [rsp + 8], rax
            mov     rax, qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt@GOTPCREL]
            mov     qword ptr [rsp + 16], rax
            lea     rax, [rip + .Lanon.460b7f3ee3193f887017359a1e30dfa7.2]
            mov     qword ptr [rsp + 24], rax
            mov     qword ptr [rsp + 32], 2
            mov     qword ptr [rsp + 56], 0
            lea     rax, [rsp + 8]
            mov     qword ptr [rsp + 40], rax
            mov     qword ptr [rsp + 48], 1
            lea     rdi, [rsp + 24]
            call    qword ptr [rip + std::io::stdio::_print@GOTPCREL]
            add     rsp, 72
            ret
    
    example::baz:
            sub     rsp, 72
            mov     dword ptr [rsp + 4], edi
            lea     rax, [rsp + 4]
            mov     qword ptr [rsp + 8], rax
            mov     rax, qword ptr [rip + core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt@GOTPCREL]
            mov     qword ptr [rsp + 16], rax
            lea     rax, [rip + .Lanon.460b7f3ee3193f887017359a1e30dfa7.2]
            mov     qword ptr [rsp + 24], rax
            mov     qword ptr [rsp + 32], 2
            mov     qword ptr [rsp + 56], 0
            lea     rax, [rsp + 8]
            mov     qword ptr [rsp + 40], rax
            mov     qword ptr [rsp + 48], 1
            lea     rdi, [rsp + 24]
            call    qword ptr [rip + std::io::stdio::_print@GOTPCREL]
            add     rsp, 72
            ret
    
    .Lanon.460b7f3ee3193f887017359a1e30dfa7.0:
            .ascii  "Hello "
    
    .Lanon.460b7f3ee3193f887017359a1e30dfa7.1:
            .byte   10
    
    .Lanon.460b7f3ee3193f887017359a1e30dfa7.2:
            .quad   .Lanon.460b7f3ee3193f887017359a1e30dfa7.0
            .asciz  "\006\000\000\000\000\000\000"
            .quad   .Lanon.460b7f3ee3193f887017359a1e30dfa7.1
            .asciz  "\001\000\000\000\000\000\000"
    

    format, however, does something completely different. So comparing it in regards of performance doesn't make much sense. Although when comparing different ways of how format can be used, the same reasoning applies to it as well, of course.