Why can I declare a str variable as mutable if Rust str is immutable? - string

According to: https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/strings.html
rust str is immutable, and cannot be used when mutability is required.
However, the following program compiles and works
fn main() {
let mut mystr = "foo";
mystr = "bar";
{
mystr = "baz";
}
println!("{:?}", mystr);
}
Can someone explain the mutability of str in Rust?
I expect let mut mystr = "foo"; to result in compilation error since str in Rust is immutable. But it compiles.

You did not change the string itself. &str is basically (*const u8, usize) - a pointer to the buffer and a length. While mutating a variable with type &str, you’re just replacing one pointer with another and not mutating the original buffer. Immutability of a string literal means that the buffer is actually linked to your binary (and, as I remember, is contained in .rodata), so you cannot change it’s contents. To actually mutate a string, use a heap-allocated one - String.

Related

Why use immutable Vector or String in Rust

I'm learning Rust and learned, that for making an expandable string or array, the String and Vec structs are used. And to modify a String or Vec, the corresponding variable needs to be annotated with mut.
let mut myString = String::from("Hello");
let mut myArray = vec![1, 2, 3];
My question is, why would you use or declare an immutable String or Vec like
let myString = String::from("Hello");
let myArray = vec![1, 2, 3];
instead of a true array or str literal like
let myString = "Hello";
let myArray = [1, 2, 3];
What would be the point of that, does it have any benefits? And what may be other use cases for immutable String's and Vec's?
Edit:
Either I am completely missing something obvious or my question isn't fully understood. I get why you want to use a mutable String or Vec over the str literal or an array, since the latter are immutable. But why would one use an immutable String or Vec over the str literal or the array (which are also immutable)?
You might then do something with that string, for example use it to populate a struct:
struct MyStruct {
field: String,
}
...
let s = String::from("hello");
let mut mystruct = MyStruct { field: s };
You could also, for example, return it from a function.
One use case could be the following:
fn main() {
let text: [u8; 6] = [0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x00];
let converted = unsafe { CStr::from_ptr(text.as_ptr() as *const c_char) }.to_string_lossy().to_string();
println!("{}", converted);
}
This is a bit constructed, but imagine you want to convert a null terminated C string (which might come from the network) from a raw pointer to some Rust string, but you don't know whether it has invalid UTF-8 in it. to_string_lossy() returns a Cow which either points to the original bytes (in case everything is valid UTF-8), but if that's not the case, it will basically copy the string and do a new allocation, replace the invalid characters with the UTF-8 replacement character and then point to that.
This is of course quite nice, because (presumably) most of the time you get away without copying the original C string, but in some cases, it might not be. But if you don't care about that and don't want to work with a Cow, it might make sense to convert it to a String, which you don't need to be mutable afterwards. But it's not possible to have a &str in case the original text contains invalid UTF-8.

Rust: If &str is supposed to be a pointer to hardcoded binary than why can I make it mutable and change it during runtime?

I am currently trying to understand the difference between &str, str, and String in Rust. I am very new to the programming language and have been banging my head on this for a while. I get the idea that String has a length and pointer that is stored on the stack and that the pointer points to some data on the heap, which contains the string data. I also get that it is stored on the heap because we don't know how much memory its string data will take up at runtime and therefore it can't be stored on the stack. For str, I understand that it is a hardcoded value in binary, which means that it must be immutable and that the only way we can get to it is with a reference: &str. If an &str must be immutable. Then why doesn't the following code result in a compiler error? Please help. I have been searching the internet and this website for hours now and I can't find an answer.
let mut s: &str = "foo";
s = "foobar";
The str itself is immutable, but the &str is a reference to a string. When you do s = "foobar" you're making s point to a different string. Here's an example that should hopefully illustrate this... rust playground.
fn main() {
let mut s: &str = "foo";
let p = s;
s = "foobar";
println!("{:?}", p);
println!("{:?}", s);
}
The rust book on pointers might also be a helpful resource to understanding pointers.
In this example it's not the str that is mutable, it's the &.
s is storing a reference to some str, s = "foobar" stores a different reference to a different str at the same locaton s.
Note the difference from let s: &mut str = "foobar", which would allow for mutating the string slice even though s is not marked as mutable.

Cannot push string to vec<&str> [duplicate]

There are several questions that seem to be about the same problem I'm having. For example see here and here. Basically I'm trying to build a String in a local function, but then return it as a &str. Slicing isn't working because the lifetime is too short. I can't use str directly in the function because I need to build it dynamically. However, I'd also prefer not to return a String since the nature of the object this is going into is static once it's built. Is there a way to have my cake and eat it too?
Here's a minimal non-compiling reproduction:
fn return_str<'a>() -> &'a str {
let mut string = "".to_string();
for i in 0..10 {
string.push_str("ACTG");
}
&string[..]
}
No, you cannot do it. There are at least two explanations why it is so.
First, remember that references are borrowed, i.e. they point to some data but do not own it, it is owned by someone else. In this particular case the string, a slice to which you want to return, is owned by the function because it is stored in a local variable.
When the function exits, all its local variables are destroyed; this involves calling destructors, and the destructor of String frees the memory used by the string. However, you want to return a borrowed reference pointing to the data allocated for that string. It means that the returned reference immediately becomes dangling - it points to invalid memory!
Rust was created, among everything else, to prevent such problems. Therefore, in Rust it is impossible to return a reference pointing into local variables of the function, which is possible in languages like C.
There is also another explanation, slightly more formal. Let's look at your function signature:
fn return_str<'a>() -> &'a str
Remember that lifetime and generic parameters are, well, parameters: they are set by the caller of the function. For example, some other function may call it like this:
let s: &'static str = return_str();
This requires 'a to be 'static, but it is of course impossible - your function does not return a reference to a static memory, it returns a reference with a strictly lesser lifetime. Thus such function definition is unsound and is prohibited by the compiler.
Anyway, in such situations you need to return a value of an owned type, in this particular case it will be an owned String:
fn return_str() -> String {
let mut string = String::new();
for _ in 0..10 {
string.push_str("ACTG");
}
string
}
In certain cases, you are passed a string slice and may conditionally want to create a new string. In these cases, you can return a Cow. This allows for the reference when possible and an owned String otherwise:
use std::borrow::Cow;
fn return_str<'a>(name: &'a str) -> Cow<'a, str> {
if name.is_empty() {
let name = "ACTG".repeat(10);
name.into()
} else {
name.into()
}
}
You can choose to leak memory to convert a String to a &'static str:
fn return_str() -> &'static str {
let string = "ACTG".repeat(10);
Box::leak(string.into_boxed_str())
}
This is a really bad idea in many cases as the memory usage will grow forever every time this function is called.
If you wanted to return the same string every call, see also:
How to create a static string at compile time
The problem is that you are trying to create a reference to a string that will disappear when the function returns.
A simple solution in this case is to pass in the empty string to the function. This will explicitly ensure that the referred string will still exist in the scope where the function returns:
fn return_str(s: &mut String) -> &str {
for _ in 0..10 {
s.push_str("ACTG");
}
&s[..]
}
fn main() {
let mut s = String::new();
let s = return_str(&mut s);
assert_eq!("ACTGACTGACTGACTGACTGACTGACTGACTGACTGACTG", s);
}
Code in Rust Playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2499ded42d3ee92d6023161fe82e9b5f
This is an old question but a very common one. There are many answers but none of them addresses the glaring misconception people have about the strings and string slices, which stems from not knowing their true nature.
But lets start with the obvious question before addressing the implied one: Can we return a reference to a local variable?
What we are asking to achieve is the textbook definition of a dangling pointer. Local variables will be dropped when the function completes its execution. In other words they will be pop off the execution stack and any reference to the local variables then on will be pointing to some garbage data.
Best course of action is either returning the string or its clone. No need to obsess over the speed.
However, I believe the essence of the question is if there is a way to convert a String into an str? The answer is no and this is where the misconception lies:
You can not turn a String into an str by borrowing it. Because a String is heap allocated. If you take a reference to it, you still be using heap allocated data but through a reference. str, on the other hand, is stored directly in the data section of the executable file and it is static. When you take a reference to a string, you will get matching type signature for common string manipulations, not an actual &str.
You can check out this post for detailed explanation:
What are the differences between Rust's `String` and `str`?
Now, there may be a workaround for this particular use case if you absolutely use static text:
Since you use combinations of four bases A, C, G, T, in groups of four, you can create a list of all possible outcomes as &str and use them through some data structure. You will jump some hoops but certainly doable.
if it is possible to create the resulting STRING in a static way at compile time, this would be a solution without memory leaking
#[macro_use]
extern crate lazy_static;
fn return_str<'a>() -> &'a str {
lazy_static! {
static ref STRING: String = {
"ACTG".repeat(10)
};
}
&STRING
}
Yes you can - the method replace_range provides a work around -
let a = "0123456789";
//println!("{}",a[3..5]); fails - doesn't have a size known at compile-time
let mut b = String::from(a);
b.replace_range(5..,"");
b.replace_range(0..2,"");
println!("{}",b); //succeeds
It took blood sweat and tears to achieve this!

Converting String to &str with lifetime [duplicate]

There are several questions that seem to be about the same problem I'm having. For example see here and here. Basically I'm trying to build a String in a local function, but then return it as a &str. Slicing isn't working because the lifetime is too short. I can't use str directly in the function because I need to build it dynamically. However, I'd also prefer not to return a String since the nature of the object this is going into is static once it's built. Is there a way to have my cake and eat it too?
Here's a minimal non-compiling reproduction:
fn return_str<'a>() -> &'a str {
let mut string = "".to_string();
for i in 0..10 {
string.push_str("ACTG");
}
&string[..]
}
No, you cannot do it. There are at least two explanations why it is so.
First, remember that references are borrowed, i.e. they point to some data but do not own it, it is owned by someone else. In this particular case the string, a slice to which you want to return, is owned by the function because it is stored in a local variable.
When the function exits, all its local variables are destroyed; this involves calling destructors, and the destructor of String frees the memory used by the string. However, you want to return a borrowed reference pointing to the data allocated for that string. It means that the returned reference immediately becomes dangling - it points to invalid memory!
Rust was created, among everything else, to prevent such problems. Therefore, in Rust it is impossible to return a reference pointing into local variables of the function, which is possible in languages like C.
There is also another explanation, slightly more formal. Let's look at your function signature:
fn return_str<'a>() -> &'a str
Remember that lifetime and generic parameters are, well, parameters: they are set by the caller of the function. For example, some other function may call it like this:
let s: &'static str = return_str();
This requires 'a to be 'static, but it is of course impossible - your function does not return a reference to a static memory, it returns a reference with a strictly lesser lifetime. Thus such function definition is unsound and is prohibited by the compiler.
Anyway, in such situations you need to return a value of an owned type, in this particular case it will be an owned String:
fn return_str() -> String {
let mut string = String::new();
for _ in 0..10 {
string.push_str("ACTG");
}
string
}
In certain cases, you are passed a string slice and may conditionally want to create a new string. In these cases, you can return a Cow. This allows for the reference when possible and an owned String otherwise:
use std::borrow::Cow;
fn return_str<'a>(name: &'a str) -> Cow<'a, str> {
if name.is_empty() {
let name = "ACTG".repeat(10);
name.into()
} else {
name.into()
}
}
You can choose to leak memory to convert a String to a &'static str:
fn return_str() -> &'static str {
let string = "ACTG".repeat(10);
Box::leak(string.into_boxed_str())
}
This is a really bad idea in many cases as the memory usage will grow forever every time this function is called.
If you wanted to return the same string every call, see also:
How to create a static string at compile time
The problem is that you are trying to create a reference to a string that will disappear when the function returns.
A simple solution in this case is to pass in the empty string to the function. This will explicitly ensure that the referred string will still exist in the scope where the function returns:
fn return_str(s: &mut String) -> &str {
for _ in 0..10 {
s.push_str("ACTG");
}
&s[..]
}
fn main() {
let mut s = String::new();
let s = return_str(&mut s);
assert_eq!("ACTGACTGACTGACTGACTGACTGACTGACTGACTGACTG", s);
}
Code in Rust Playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2499ded42d3ee92d6023161fe82e9b5f
This is an old question but a very common one. There are many answers but none of them addresses the glaring misconception people have about the strings and string slices, which stems from not knowing their true nature.
But lets start with the obvious question before addressing the implied one: Can we return a reference to a local variable?
What we are asking to achieve is the textbook definition of a dangling pointer. Local variables will be dropped when the function completes its execution. In other words they will be pop off the execution stack and any reference to the local variables then on will be pointing to some garbage data.
Best course of action is either returning the string or its clone. No need to obsess over the speed.
However, I believe the essence of the question is if there is a way to convert a String into an str? The answer is no and this is where the misconception lies:
You can not turn a String into an str by borrowing it. Because a String is heap allocated. If you take a reference to it, you still be using heap allocated data but through a reference. str, on the other hand, is stored directly in the data section of the executable file and it is static. When you take a reference to a string, you will get matching type signature for common string manipulations, not an actual &str.
You can check out this post for detailed explanation:
What are the differences between Rust's `String` and `str`?
Now, there may be a workaround for this particular use case if you absolutely use static text:
Since you use combinations of four bases A, C, G, T, in groups of four, you can create a list of all possible outcomes as &str and use them through some data structure. You will jump some hoops but certainly doable.
if it is possible to create the resulting STRING in a static way at compile time, this would be a solution without memory leaking
#[macro_use]
extern crate lazy_static;
fn return_str<'a>() -> &'a str {
lazy_static! {
static ref STRING: String = {
"ACTG".repeat(10)
};
}
&STRING
}
Yes you can - the method replace_range provides a work around -
let a = "0123456789";
//println!("{}",a[3..5]); fails - doesn't have a size known at compile-time
let mut b = String::from(a);
b.replace_range(5..,"");
b.replace_range(0..2,"");
println!("{}",b); //succeeds
It took blood sweat and tears to achieve this!

How to convert a String into a &'static str

How do I convert a String into a &str? More specifically, I would like to convert it into a str with the static lifetime (&'static str).
Updated for Rust 1.0
You cannot obtain &'static str from a String because Strings may not live for the entire life of your program, and that's what &'static lifetime means. You can only get a slice parameterized by String own lifetime from it.
To go from a String to a slice &'a str you can use slicing syntax:
let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..]; // take a full slice of the string
Alternatively, you can use the fact that String implements Deref<Target=str> and perform an explicit reborrowing:
let s_slice: &str = &*s; // s : String
// *s : str (via Deref<Target=str>)
// &*s: &str
There is even another way which allows for even more concise syntax but it can only be used if the compiler is able to determine the desired target type (e.g. in function arguments or explicitly typed variable bindings). It is called deref coercion and it allows using just & operator, and the compiler will automatically insert an appropriate amount of *s based on the context:
let s_slice: &str = &s; // okay
fn take_name(name: &str) { ... }
take_name(&s); // okay as well
let not_correct = &s; // this will give &String, not &str,
// because the compiler does not know
// that you want a &str
Note that this pattern is not unique for String/&str - you can use it with every pair of types which are connected through Deref, for example, with CString/CStr and OsString/OsStr from std::ffi module or PathBuf/Path from std::path module.
You can do it, but it involves leaking the memory of the String. This is not something you should do lightly. By leaking the memory of the String, we guarantee that the memory will never be freed (thus the leak). Therefore, any references to the inner object can be interpreted as having the 'static lifetime.
fn string_to_static_str(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
fn main() {
let mut s = String::new();
std::io::stdin().read_line(&mut s).unwrap();
let s: &'static str = string_to_static_str(s);
}
As of Rust version 1.26, it is possible to convert a String to &'static str without using unsafe code:
fn string_to_static_str(s: String) -> &'static str {
Box::leak(s.into_boxed_str())
}
This converts the String instance into a boxed str and immediately leaks it. This frees all excess capacity the string may currently occupy.
Note that there are almost always solutions that are preferable over leaking objects, e.g. using the crossbeam crate if you want to share state between threads.
TL;DR: you can get a &'static str from a String which itself has a 'static lifetime.
Although the other answers are correct and most useful, there's a (not so useful) edge case, where you can indeed convert a String to a &'static str:
The lifetime of a reference must always be shorter or equal to the lifetime of the referenced object. I.e. the referenced object has to live longer (or equal long) than the reference. Since 'static means the entire lifetime of a program, a longer lifetime does not exist. But an equal lifetime will be sufficient. So if a String has a lifetime of 'static, you can get a &'static str reference from it.
Creating a static of type String has theoretically become possible with Rust 1.31 when the const fn feature was released. Unfortunately, the only const function returning a String is String::new() currently, and it's still behind a feature gate (so Rust nightly is required for now).
So the following code does the desired conversion (using nightly) ...and actually has no practical use except for completeness of showing that it is possible in this edge case.
#![feature(const_string_new)]
static MY_STRING: String = String::new();
fn do_something(_: &'static str) {
// ...
}
fn main() {
do_something(&MY_STRING);
}

Resources