dubugger
dubugger

Reputation: 109

How to change a String into a Vec and can also modify Vec's value in Rust?

I want to change a String into a vector of bytes and also modify its value, I have looked up and find How do I convert a string into a vector of bytes in rust? but this can only get a reference and I cannot modify the vector. I want a to be 0, b to be 1 and so on, so after changing it into bytes I also need to subtract 97. Here is my attempt:

fn main() {
    let s: String = "abcdefg".to_string();
    let mut vec = (s.as_bytes()).clone();
    println!("{:?}", vec);
    for i in 0..vec.len() {
        vec[i] -= 97;
    }
    println!("{:?}", vec);
}

but the compiler says

error[E0594]: cannot assign to `vec[_]`, which is behind a `&` reference

Can anyone help me to fix this?

Upvotes: 0

Views: 451

Answers (3)

isaactfa
isaactfa

Reputation: 6657

You could get a Vec<u8> out of the String with the into_bytes method. An even better way, though, may be to iterate over the String's bytes with the bytes method, do the maths on the fly, and then collect the result:

fn main() {
    let s = "abcdefg";
    let vec: Vec<u8> = s.bytes().map(|b| b - b'a').collect();
    println!("{:?}", vec); // [0, 1, 2, 3, 4, 5, 6]
}

But as @SvenMarnach correctly points out, this won't re-use s's buffer but allocate a new one. So, unless you need s again, the into_bytes method will be more efficient.

Upvotes: 4

Caesar
Caesar

Reputation: 8544

To understand what's going on, check the type of the vec variable. If you don't have an IDE/editor that can display the type to you, you can do this:

let mut vec: () = (s.as_bytes()).clone();

The resulting error message is explanative:

3 |     let mut vec: () = (s.as_bytes()).clone();
  |                  --   ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&[u8]`

So, what's happening is that the .clone() simply cloned the reference returned by as_bytes(), and didn't create a Vec<u8> from the &[u8]. In general, you can use .to_owned() in this kind of case, but in this specific case, using .into_bytes() on the String is best.

Upvotes: 3

Sven Marnach
Sven Marnach

Reputation: 602485

Strings in Rust are encoded in UTF-8. The (safe) interface of the String type enforces that the underlying buffer always is valid UTF-8, so it can't allow direct arbitrary byte modifications. However, you can convert a String into a Vec<u8> using the into_bytes() mehod. You can then modify the vector, and potentially convert it back to a string using String::from_utf8() if desired. The last step will verify that the buffer still is vaid UTF-8, and will fail if it isn't.

Instead of modifying the bytes of the string, you could also consider modifying the characters, which are potentially encoded by multiple bytes in the UTF-8 encoding. You can iterate over the characters of the string using the chars() method, convert each character to whatever you want, and then collect into a new string, or alternatively into a vector of integers, depending on your needs.

Upvotes: 3

Related Questions