0
votes

Alright so, I'm about a month in on Rust and doing more mundane tasks in it just for exercise. I came across the calamine crate to read in data from excel. I thought I was well on my way to understand burrowing and ownership, but this one is new and even reading some other examples and looking in the docs didn't help explain it or I at least haven't came across it. So a basic for loop

 for row in r.rows() {
        let writer1 = row[11].to_string(); 
        if let Some(cap) = exp.captures(&writer1) { // borrow here
            println!("{} --- {}", &cap[1], &cap[2]);
        } else {
            println!("{}", &writer1); // and borrow here
        }
        // This works fine... great
        // writer1 is type String
        // row     is type &[calamine::datatype::DataType]

        let doing_this: Vec<&str> = writer1.split_whitespace().collect();

        vecs.push(doing_this); // assume vecs exists above for
    }

When I go to push the collection "doing_this" into a vector it gives the E0597 error. Can anyone help explain what is going on? I assume lifetimes but I already created a string from the column and took ownership.

1
writer1 lives in the scope of the loop. vecs lives outside. writer1 is dropped at the end of the loop, but vecs probably is used later. But its contents doing_this depend (reference) on the dropped contents of writer1. If doing_this were a Vec<String> (owned) there would be no problem.CoronA
I follow you @CoronA doing_this is holding a &str ref to writer1 that eventually goes out of scope. Though split_whitespace won't allow collect to be anything other than the underlying string, as it is an &str iter so if you use collect it has to be a Vec<&str>. I'm not new to coding but this is way different to think about. I added my solution though I know there has to be something a bit more canonical. I was hoping for a clone().collect()...JustDave
You should be able to use .map(String::from), which will do same thing without additional closure noise. You cannot use clone here, because you're providing &str's. Not that it's a bad thing, &String is often code smell, because you provide unnecessary indirection for little to no gain. Also, the methods you use deliberately provide &str, as you don't always want to copy data, which is both more performant and doesn't allocate more memory unless you yourself declare with String::from/str::to_owned.Sahsahae
@Sahsahae I find myself unable to use the value in place due to "temp free errors" so I use a let binding for an intermediate and clone it so that I don't get those errors. So because I make a clone I don't want to keep cloning it or taking a full slice with something like &writer1[] <- that looks like a code smell and I reuse it so I can't move it so the only option is &String. I deliberately say <&str> because that is the is a &str iter co collect is &str until I clone it.JustDave

1 Answers

0
votes
        // changed this 
        let doing_this: Vec<&str> = writer1.split_whitespace().collect();


        // to this
        let doing_this: Vec<String> =
            writer1.split_whitespace().map(|x| x.to_owned()).collect();

        // or as suggested to clean up the closure
        let doing_this: Vec<String> =
            writer1.split_whitespace().map(String::from).collect();