2015-04-02 23 views
3

假設我在Rust中有一個結構向量。結構相當大。當我要插入一個新的,我寫了這樣的代碼:Rust是否優化通過臨時結構的價值?

my_vec.push(MyStruct {field1: value1, field2: value2, ... }); 

推定義是

fn push(&mut self, value: T) 

這意味着是按值傳遞的價值。我想知道Rust是否先創建一個臨時對象,然後拷貝到推送函數還是優化代碼,以便不創建和複製臨時對象?

回答

3

讓我們來看看。 This program

struct LotsOfBytes { 
    bytes: [u8; 1024] 
} 

#[inline(never)] 
fn consume(mut lob: LotsOfBytes) { 
} 

fn main() { 
    let lob = LotsOfBytes { bytes: [0; 1024] }; 
    consume(lob); 
} 

編譯以下LLVM IR代碼:

%LotsOfBytes = type { [1024 x i8] } 

; Function Attrs: noinline nounwind uwtable 
define internal fastcc void @_ZN7consume20hf098deecafa4b74bkaaE(%LotsOfBytes* noalias nocapture dereferenceable(1024)) unnamed_addr #0 { 
entry-block: 
    %1 = getelementptr inbounds %LotsOfBytes* %0, i64 0, i32 0, i64 0 
    tail call void @llvm.lifetime.end(i64 1024, i8* %1) 
    ret void 
} 

; Function Attrs: nounwind uwtable 
define internal void @_ZN4main20hf3cbebd3154c5390qaaE() unnamed_addr #2 { 
entry-block: 
    %lob = alloca %LotsOfBytes, align 8 
    %lob1 = getelementptr inbounds %LotsOfBytes* %lob, i64 0, i32 0, i64 0 
    %arg = alloca %LotsOfBytes, align 8 
    %0 = getelementptr inbounds %LotsOfBytes* %lob, i64 0, i32 0, i64 0 
    call void @llvm.lifetime.start(i64 1024, i8* %0) 
    call void @llvm.memset.p0i8.i64(i8* %lob1, i8 0, i64 1024, i32 8, i1 false) 
    %1 = getelementptr inbounds %LotsOfBytes* %arg, i64 0, i32 0, i64 0 
    call void @llvm.lifetime.start(i64 1024, i8* %1) 
    call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %0, i64 1024, i32 8, i1 false) 
    call fastcc void @_ZN7consume20hf098deecafa4b74bkaaE(%LotsOfBytes* noalias nocapture dereferenceable(1024) %arg) 
    call void @llvm.lifetime.end(i64 1024, i8* %1) 
    call void @llvm.lifetime.end(i64 1024, i8* %0) 
    ret void 
} 

這條線路是特別有趣:

call fastcc void @_ZN7consume20hf098deecafa4b74bkaaE(%LotsOfBytes* noalias nocapture dereferenceable(1024) %arg) 

如果我理解正確的話,這意味着consume被調用一個指向LotsOfBytes的指針,所以是的,rustc優化了按值傳遞的大型結構。