简体   繁体   中英

How does exactly rust handle return values

I've got question about my code:

pub fn get_signals(path: &String) -> Vec<Vec<f64>> {
    let mut rdr = csv::ReaderBuilder::new().delimiter(b';').from_path(&path).unwrap();

    let mut signals: Vec<Vec<f64>> = Vec::new();

    for record in rdr.records(){
        let mut r = record.unwrap();
        for (i, value) in r.iter().enumerate(){
            match signals.get(i){
                Some(_) => {},
                None    => signals.push(Vec::new())
            }
            signals[i].push(value.parse::<f64>().unwrap());
        }
    }

    signals
}

How exactly does Rust handle return? When I, for example write let signals = get_signal(&"data.csv".to_string()); does Rust assume I want a new instance of Vec(copies all the data) or just pass a pointer to previously allocated(via Vec::new() ) memory? What is the most efficient way to do this? Also, what happens with rdr ? I assume, given Rusts memory safety, it's destroyed.

How exactly does Rust handle return?

The only guarantee Rust, the language, makes is that values are never cloned without an explicit .clone() in the code. Therefore, from a semantic point of view, the value is moved which will not require allocating memory.

does Rust assume I want a new instance of Vec (copies all the data) or just pass a pointer to previously allocated (via Vec::new() ) memory?

This is implementation specific, and part of the ABI (Application Binary Interface). The Rust ABI is not formalized, and not stable, so there is no standard describing it and no guarantee about this holding up.

Furthermore, this will depend on whether the function call is inlined or not . If the function call is inlined, there is of course no return any longer yet the same behavior should be observed.

For small values , they should be returned via a register (or a couple of registers).

For larger values :

  • the caller should reserve memory on the stack (properly sized and aligned) and pass a pointer to this area to the callee,
  • the callee will then construct the return value at the place pointed to, so that by the time it returns the value exists there for the caller to use.

Note: by the size here is the size on the stack, as returned by std::mem::size_of ; so size_of::<Vec<_>>() == 24 on 64-bits architecture.

What is the most efficient way to do this?

Returning is as efficient as it gets for a single call .

If however you find yourself in a situation where, say, you want to read a file line by line, then it makes sense to reuse the buffer from one call to the other which can be accomplished either by:

  • taking a &mut references to the buffer ( String or Vec<u8> say),
  • or taking a buffer by value and returning it.

The point being to avoid memory allocations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM