what is the difference between these lines in RUST? - rust

what is the difference between these two scenario I have the same functionality with 2 different model and it is a bit confusing for me !
//model_1
let mut my_str = String::from("ali");
let str1 = &mut my_str; // defining str1 without "mut"
//model_2
let mut my_str = String::from("ali");
let mut str1 = &mut my_str // defining str1 with "mut"

Let's start with the similarity: neither of them compiles, because you cannot acquire a mutable reference (&mut) of an object that is itself not defined as mut.
As for the correct version, it is the following:
let mut my_str = String::from("ali");
let str2 = &mut my_str;
my_str needs to be defined as mutable if we are to grab a mutable reference to it, so that makes the first line unambiguous.
On the second line, the mut prefix to str2 is only necessary if you are going to modify what reference str2 points to. As long as you are only modifying the content of the string (without changing what string you are modifying) you do not need it.

Related

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

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.

Parse integer from from iterator

Is there a way to parse an integer from a str in rust, like my_str.parse(), but yielding an iterator to the point after the parsed integer? Something like this:
let my_str = "1234x";
let mut iter = my_str.chars();
assert_eq!(iter.parse_and_advance().unwrap(), 1234);
assert_eq!(iter.next(), Some('x'));
You don't need iterators at all. You can first use str::find to find the first non-numeric value, then use str::split_at to split the string there so you can parse the first half and convert the second half into an iterator:
let str = "1234x";
let non_letter = str.find(|c: char| c != '-' && !c.is_numeric());
let (num, rest) = str.split_at(non_letter.unwrap_or(str.len()));
let num: i32 = num.parse().unwrap();
let mut rest = rest.chars();
assert_eq!(num, 1234);
assert_eq!(rest.next(), Some('x'));
Playground link
Note that, as stated in the comments, there's a little more nuance than this to extracting the initial number, but depending on your usecase it won't be an issue.

How to destroy reference within scope?

All I was trying to do is copy a vector to another vector by iterating through it. I am getting the error borrowed value does not live long enough. And I get it why I am seeing this, that's because the invalid memory reference must not live outside scope. My question is, how can I destroy the reference as well in the scope after using it?
fn main() {
let x: Vec<&str> = vec!["a","b","c","d"];
let mut y: Vec<&str> = vec![];
let z: String = String::from("xy");
let p: &String = &z;
for i in x {
let k = [i, p].concat();
let q: &str = &k;
y.push(q);
}
println!("{:?}",y);
}
I want to keep Vec<&str> for mut y. I don't want to change it to Vec<String> although that's possible, because I want to keep it on the stack, not heap. Is that possible?
k is getting allocated on the heap regardless of how you define your Vec, the problem is the scope of k.
for i in x {
let k = [i, p].concat();
let q: &str = &k;
y.push(q);
} // <- k goes out of scope at the end of each iteration.
y can not hold a reference to k because it will not exist when the loop finishes.
As you pointed out, Vec<String> will solve your issue because String Is an owned value, where &str is a borrowed one, and you are attempting to borrow from a String (k) that has a shorter lifetime than y.

What's the semantic of assignment in Rust?

How could know the type of a binding if I use auto type deduction when creating a binding? what if the expression on the right side is a borrow(like let x = &5;), will it be value or a borrow? What will happen if I re-assign a borrow or a value?
Just for check, I do can re-assign a borrow if I use let mut x: &mut T = &mut T{}; or let mut x:&T = & T{};, right?
I sense some confusion between binding and assigning:
Binding introduces a new variable, and associates it to a value,
Assigning overwrites a value with another.
This can be illustrated in two simple lines:
let mut x = 5; // Binding
x = 10; // Assigning
A binding may appear in multiple places in Rust:
let statements,
if let/while let conditions,
cases in a match expression,
and even in a for expression, on the left side of in.
Whenever there is a binding, Rust's grammar also allows pattern matching:
in the case of let statements and for expressions, the patterns must be irrefutable,
in the case of if let, while let and match cases, the patterns may fail to match.
Pattern matching means that the type of the variable introduced by the binding differs based on how the binding is made:
let x = &5; // x: &i32
let &y = &5; // y: i32
Assigning always requires using =, the assignment operator.
When assigning, the former value is overwritten, and drop is called on it if it implements Drop.
let mut x = 5;
x = 6;
// Now x == 6, drop was not called because it's a i32.
let mut s = String::from("Hello, World!");
s = String::from("Hello, 神秘德里克!");
// Now s == "Hello, 神秘德里克!", drop was called because it's a String.
The value that is overwritten may be as simple as an integer or float, a more involved struct or enum, or a reference.
let mut r = &5;
r = &6;
// Now r points to 6, drop was not called as it's a reference.
Overwriting a reference does not overwrite the value pointed to by the reference, but the reference itself. The original value still lives on, and will be dropped when it's ready.
To overwrite the pointed to value, one needs to use *, the dereference operator:
let mut x = 5;
let r = &mut x;
*r = 6;
// r still points to x, and now x = 6.
If the type of the dereferenced value requires it, drop will be called:
let mut s = String::from("Hello, World!");
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
// r still points to s, and now s = "Hello, 神秘德里克!".
I invite you to use to playground to and toy around, you can start from here:
fn main() {
let mut s = String::from("Hello, World!");
{
let r = &mut s;
*r = String::from("Hello, 神秘德里克!");
}
println!("{}", s);
}
Hopefully, things should be a little clearer now, so let's check your samples.
let x = &5;
x is a reference to i32 (&i32). What happens is that the compiler will introduce a temporary in which 5 is stored, and then borrow this temporary.
let mut x: &mut T = T{};
Is impossible. The type of T{} is T not &mut T, so this fails to compile. You could change it to let mut x: &mut T = &mut T{};.
And your last example is similar.

What is the differences between the two slice in Rust?

let s1 = String::from("hello world.");
let r1 = &s1;
let sl1 = &s1[..];
let sl2 = &r1[..];
let sl3 = r1[..];
println!("{}", sl3);
What is the difference between sl1 and sl2, and why sl3 is invalid? Isn't r1 a reference already, why need &?
The compiler dereferences the output of Index::index when desugaring the indexing syntax [] (see related question and its answers). Using explicit type annotations, the types of the bindings are thus as follows:
let r1: &str = &s1;
let sl1: &str = &s1[..];
let sl2: &str = &r1[..];
let sl3: str = r1[..];
str, being an unsized type, cannot be put on the stack and therefore cannot be used as the type for a local variable binding sl3, hence the compile error.

Resources