I am trying to edit a string in place by passing it to mutate(), see below.
Simplified example:
fn mutate(string: &mut &str) -> &str {
string[0] = 'a'; // mutate string
string
}
fn do_something(string: &str) {
println!("{}", string);
}
fn main() {
let string = "Hello, world!";
loop {
string = mutate(&mut string);
do_something(string);
}
}
But I get the following compilation error:
main.rs:1:33: 1:37 error: missing lifetime specifier [E0106]
main.rs:1 fn mutate(string: &mut &str) -> &str {
^~~~
main.rs:1:33: 1:37 help: this function's return type contains a borrowed value, but the signature does not say which one of `string`'s 2 elided lifetimes it is borrowed from
main.rs:1 fn mutate(string: &mut &str) -> &str {
^~~~
Why do I get this error and how can I achieve what I want?
Strings in Python are immutable. Therefore, we cannot modify strings in place.
To convert a string in to function "eval()" method should be used. This method takes a string as a parameter and converts it into a function.
Yes, no problem at all. If you really want a reference, section 21.4. 5/2 of the C++11 standard.
You can't change a string slice at all. &mut &str
is not an appropriate type anyway, because it literally is a mutable pointer to an immutable slice. And all string slices are immutable.
In Rust strings are valid UTF-8 sequences, and UTF-8 is a variable-width encoding. Consequently, in general changing a character may change the length of the string in bytes. This can't be done with slices (because they always have fixed length) and it may cause reallocation for owned strings. Moreover, in 99% of cases changing a character inside a string is not what you really want.
In order to do what you want with unicode code points you need to do something like this:
fn replace_char_at(s: &str, idx: uint, c: char) -> String {
let mut r = String::with_capacity(s.len());
for (i, d) in s.char_indices() {
r.push(if i == idx { c } else { d });
}
r
}
However, this has O(n)
efficiency because it has to iterate through the original slice, and it also won't work correctly with complex characters - it may replace a letter but leave an accent or vice versa.
More correct way for text processing is to iterate through grapheme clusters, it will take diacritics and other similar things correctly (mostly):
fn replace_grapheme_at(s: &str, idx: uint, c: &str) -> String {
let mut r = String::with_capacity(s.len());
for (i, g) in s.grapheme_indices(true) {
r.push_str(if i == idx { c } else { g });
}
r
}
There is also some support for pure ASCII strings in std::ascii
module, but it is likely to be reformed soon. Anyway, that's how it could be used:
fn replace_ascii_char_at(s: String, idx: uint, c: char) -> String {
let mut ascii_s = s.into_ascii();
ascii_s[idx] = c.to_ascii();
String::from_utf8(ascii_s.into_bytes()).unwrap()
}
It will panic if either s
contains non-ASCII characters or c
is not an ASCII character.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With