Non-mut variables is mutable leading to crash - rust

I ran across a weird case where Rust was telling me that I didn't need mut on a variable, even though I was clearly mutating it! After some fiddling around I managed to get the following code to compile which just looks broken.
fn main() {
let x: u32;
loop {
match 1 {
1 => {}
_ => {
x = 5;
break;
}
}
}
dbg!(x);
}
Running it (playground) results in some kind of crash. What's going on here? Is this a compiler bug? I tried it on nightly and it still times out.

This also compiles:
let x: u32;
if false {
x = 5;
}
As well as:
let x: u32;
x = 5;
As #trentcl mentions, this is deferred initialization, which is why it is accepted.

Related

How can I implement the typestate pattern based on a discriminator? [duplicate]

I was wondering if it was possible to return different types depending on the conditions in the function:
This code will work if you remove '|| bool' and the 'if/else' statements.
Thanks in advance.
fn main() {
let vector: Vec<i32> = vec![0, 2, 5, 8, 9];
let targetL i32 = 3;
let found_item = linear_search(vector, target);
println!("{}", &found_item);
}
fn linear_search(vector: Vec<i32>, target: i32) -> i32 || bool {
let mut found: i32 = 0;
for item in vector {
if item == target {
found = item;
break
}
}
if found == 0 {
false
} else {
found
}
}
The precise type must be known at compile time (and is subsequently erased). You cannot decide arbitrarily which types to return at runtime.
However, you can do you've tried to do, by wrapping the types into a generic enum (which replaces the || in your code):
enum TypeOr<S, T> {
Left(S),
Right(T),
}
fn linear_search(vector: ...) -> TypeOr<i32, bool> { //...
The downside is that you must unwrap the value from the enum before you can do anything else with the result. However, this isn't so arduous in practice.
This is essentially a generalised version of the commonly used Option and Result types.
Edit: In fact, in your case, you are served very nicely by the semantics of the Option type: you never return true, so you may equate the None result with the false result your function returns, and this captures the idea you're trying to express: either your linear search finds the target and returns it (Some(found)), or it does not, and has nothing to return (None).

Does Rust have anything similar to CallerMembrerName in C#

I'd like to know the name of the function that called my function in Rust.
In C# there's CallerMemberName attribute which tells the compiler to replace the value of a string argument to which it's applied with the name of the caller.
Does Rust have anything like that?
I don't know of a compile time solution, but you can use the backtrace functionality to resolve it at runtime.
use backtrace::Backtrace;
fn caller_name_slow() -> Option<String> {
let backtrace = Backtrace::new();
let symbolname = backtrace.frames().get(2)?.symbols().first()?.name();
symbolname.map(|s| format!("{:#?}", s))
}
fn caller_name_fast() -> Option<String> {
let mut count = 0;
let mut result = None;
backtrace::trace({
|frame| {
count += 1;
if count == 5 {
// Resolve this instruction pointer to a symbol name
backtrace::resolve_frame(frame, |symbol| {
if let Some(name) = symbol.name() {
result = Some(format!("{:#?}", name));
}
});
false
} else {
true // keep going to the next frame
}
}
});
result
}
fn my_function() {
println!("I got called by '{}'.", caller_name_slow().unwrap());
println!("I got called by '{}'.", caller_name_fast().unwrap());
}
fn main() {
my_function();
}
I got called by 'rust_tmp::main'.
I got called by 'rust_tmp::main'.
Note, however, that his is unreliable. The amount of stack frames we have to go up differs between targets and release/debug (due to inlining). For example, on my machine, in release I had to modify count == 5 to count == 2.

Recursive closure inside a function [duplicate]

This is a very simple example, but how would I do something similar to:
let fact = |x: u32| {
match x {
0 => 1,
_ => x * fact(x - 1),
}
};
I know that this specific example can be easily done with iteration, but I'm wondering if it's possible to make a recursive function in Rust for more complicated things (such as traversing trees) or if I'm required to use my own stack instead.
There are a few ways to do this.
You can put closures into a struct and pass this struct to the closure. You can even define structs inline in a function:
fn main() {
struct Fact<'s> { f: &'s dyn Fn(&Fact, u32) -> u32 }
let fact = Fact {
f: &|fact, x| if x == 0 {1} else {x * (fact.f)(fact, x - 1)}
};
println!("{}", (fact.f)(&fact, 5));
}
This gets around the problem of having an infinite type (a function that takes itself as an argument) and the problem that fact isn't yet defined inside the closure itself when one writes let fact = |x| {...} and so one can't refer to it there.
Another option is to just write a recursive function as a fn item, which can also be defined inline in a function:
fn main() {
fn fact(x: u32) -> u32 { if x == 0 {1} else {x * fact(x - 1)} }
println!("{}", fact(5));
}
This works fine if you don't need to capture anything from the environment.
One more option is to use the fn item solution but explicitly pass the args/environment you want.
fn main() {
struct FactEnv { base_case: u32 }
fn fact(env: &FactEnv, x: u32) -> u32 {
if x == 0 {env.base_case} else {x * fact(env, x - 1)}
}
let env = FactEnv { base_case: 1 };
println!("{}", fact(&env, 5));
}
All of these work with Rust 1.17 and have probably worked since version 0.6. The fn's defined inside fns are no different to those defined at the top level, except they are only accessible within the fn they are defined inside.
As of Rust 1.62 (July 2022), there's still no direct way to recurse in a closure. As the other answers have pointed out, you need at least a bit of indirection, like passing the closure to itself as an argument, or moving it into a cell after creating it. These things can work, but in my opinion they're kind of gross, and they're definitely hard for Rust beginners to follow. If you want to use recursion but you have to have a closure, for example because you need something that implements FnOnce() to use with thread::spawn, then I think the cleanest approach is to use a regular fn function for the recursive part and to wrap it in a non-recursive closure that captures the environment. Here's an example:
let x = 5;
let fact = || {
fn helper(arg: u64) -> u64 {
match arg {
0 => 1,
_ => arg * helper(arg - 1),
}
}
helper(x)
};
assert_eq!(120, fact());
Here's a really ugly and verbose solution I came up with:
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
fn main() {
let weak_holder: Rc<RefCell<Weak<dyn Fn(u32) -> u32>>> =
Rc::new(RefCell::new(Weak::<fn(u32) -> u32>::new()));
let weak_holder2 = weak_holder.clone();
let fact: Rc<dyn Fn(u32) -> u32> = Rc::new(move |x| {
let fact = weak_holder2.borrow().upgrade().unwrap();
if x == 0 {
1
} else {
x * fact(x - 1)
}
});
weak_holder.replace(Rc::downgrade(&fact));
println!("{}", fact(5)); // prints "120"
println!("{}", fact(6)); // prints "720"
}
The advantages of this are that you call the function with the expected signature (no extra arguments needed), it's a closure that can capture variables (by move), it doesn't require defining any new structs, and the closure can be returned from the function or otherwise stored in a place that outlives the scope where it was created (as an Rc<Fn...>) and it still works.
Closure is just a struct with additional contexts. Therefore, you can do this to achieve recursion (suppose you want to do factorial with recursive mutable sum):
#[derive(Default)]
struct Fact {
ans: i32,
}
impl Fact {
fn call(&mut self, n: i32) -> i32 {
if n == 0 {
self.ans = 1;
return 1;
}
self.call(n - 1);
self.ans *= n;
self.ans
}
}
To use this struct, just:
let mut fact = Fact::default();
let ans = fact.call(5);

Equivalence of iterating over filter and continue condition within iteration

To keep my code somewhat legible I extracted several data structures into a separate struct:
struct S {
x: Vec<i32>,
y: HashSet<i32>,
z: Vec<i32>,
}
That lives only within one method call and it's subcalls:
fn main() {
let mut w = S { x: vec![], y: HashSet::new(), z: vec![], };
do_part_of_the_work(&mut w);
}
fn do_part_of_the_work(w: &mut S) {
// 1. Works
for (index, &item) in w.x.iter().enumerate() {
if w.y.contains(&item) {
continue;
}
w.z[index] += 1;
}
// 2. Seems equivalent to 1. but doesn't work
for (index, &item) in w.x.iter().enumerate()
.filter(|&(_, &item)| !w.y.contains(&item)) {
w.z[index] += 1;
}
// 3. Seems equivalent to 2. and doesn't work either
for (index, &item) in w.iter_not_in_y() {
w.z[index] += 1;
}
}
impl S {
fn iter_not_in_y(&self) -> impl Iterator<Item = (usize, &i32)> {
self.x.iter().enumerate().filter(move |&(_, &item)| !self.y.contains(&item))
}
}
I'm essentially trying to do what codeblock 1. does in the form of codeblock 3., with 2. as an intermediate step that doesn't work, although these seem equivalent. Had all attributes of S been local variables, it seems that all three code blocks would have worked.
Moving the codeblock inside the impl didn't get me far either:
impl S {
fn doing_it_inside_the_struct(&mut self) {
// Doing 3. inside the struct instead, doesn't work either
for (index, &item) in self.iter_not_in_y() {
self.z[index] += 1;
}
}
}
Why doesn't block 2. work? Is it not equivalent to 1.? Could this problem be avoided by choosing a different design?
Playground
The problem with version 2:
for (index, &item) in w.x.iter().enumerate()
.filter(|&(_, &item)| !w.y.contains(&item)) {
w.z[index] += 1;
}
is that the closure for filter() captures w by reference, that is, it holds a &w. This means that the whole w is borrowed as long as this closure is alive. Then when you try to mutably borrow w.z the compiler fails.
The code in the first version uses the w.y and w.z in separated borrows and w itself is never borrowed, so it works.
The solution is to write the closure to capture only the w.y and not the w. Unfortunately there is not an easy and nice syntax for that. The nicer I can write is something like:
for (index, &item) in w.x.iter().enumerate()
.filter({
let y = &w.y;
move |&(_, &item)| !y.contains(&item)
}) {
w.z[index] += 1;
}
With the let y = &w.y; you capture only the y. Now you have to mark the closure as move or else you would capture &y, and being y a temporary that would not work.
The problem with with version 3 is similar: calling a member borrows self, that is &w so you cannot modify it afterwards. But a similar workaround would not work, because what would happen if your iter_not_in_y() implementation used self.z? You could easily get to undefined behavior.

Why doesn't the compiler raise a warning when a struct member is unread?

I have these 2 pieces of code:
fn main() {
let mut x: int = 5;
x = 6;
println!("value {}", x);
}
With this code, the compiler will raise warning:
the value is never read at let x: int = 5
But with the following code, the compiler doesn't.
struct Point {
x: int,
y: int,
}
fn main() {
let mut p = Point {x: 1i, y: 2i};
p.x = 5;
println!("value {}, {}", p.x, p.y);
}
Why does that happens? We never read the value when x = 1i. Rather, we read the value at x = 5i. So why the compiler doesn't raise warning like the code before?
I think this happens because the compiler only analyzes immediate local variables and does not go deeper into structures. I imagine that full analysis would require a rather complex algorithm, and there is little need for it.
Or maybe it is a bug in the compiler, or, more likely, an unimplemented feature. You can submit a ticket to the issue tracker if you think it is important.

Resources