FizzBuzz Function in Rust - rust

This is my code:
fn main() {
fn fizz_buzz<'a>(i: i32) -> &'a str {
if i % 15 == 0 {
"FizzBuzz"
} else if i % 5 == 0 {
"Buzz"
} else if i % 3 == 0 {
"Fizz"
} else {
&i.to_string()
}
}
for i in 1..101 {
println!("{}" , fizz_buzz(i));
}
}
The compiler gives me this error:
error[E0515]: cannot return reference to temporary value
--> src/main.rs:11:9
|
11 | &i.to_string()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
For more information about this error, try `rustc --explain E0515`.
error: could not compile `playground` due to previous error
I tried a static lifetime.

Your function will correctly give back a reference to the strings "FizzBuzz," "Buzz," and "Fizz" (whose lifetimes are static since they're compiled in) however the &i.to_string() does not have that same property. Let's look at the lifetime in detail:
When fizz_buzz is called, i is copied (because i32 implements the Copy trait) and given to it. In that else block, however, we do the following:
Create a new owned String
Return a reference to that String
however, the lifetime of that String is only as long as the fizz_buzz function call! Since we need to use its reference outside of that scope, Rust calls foul.
There are a couple ways to make this type safe. You could return owned values rather than references:
fn fizz_buzz(i: i32) -> String {
if i % 15 == 0 { String::from("FizzBuzz") }
else if i % 5 == 0 { String::from("Buzz") }
else if i % 3 == 0 { String::from("Fizz") }
else { i.to_string() }
}
Though this will end up creating a lot of identical objects on the heap (consider how many "Fizz"es there are, for instance)
The other option that I'd prefer is to have fizz_buzz return an Option<&str>, and have the calling scope handle the case when fizz_buzz gives None.
fn fizz_buzz(i: i32) -> Option<&'static str> {
if i % 15 == 0 { Some("FizzBuzz") }
else if i % 5 == 0 { Some("Buzz") }
else if i % 3 == 0 { Some("Fizz") }
else { None }
}
for i in 1..101 {
match fizz_buzz(i) {
Some(v) => println!("{}", v),
None => println!("{}", i),
}
}
As #RobinZigmond points out in the comments, you could also return an enum and implement Display for it.
use std::fmt::{self, Display};
enum FizzBuzz {
FizzBuzz,
Fizz,
Buzz,
Other(i32)
}
impl Display for FizzBuzz {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FizzBuzz => write!(f, "{}", "FizzBuzz"),
Self::Fizz => write!(f, "{}", "Fizz"),
Self::Buzz => write!(f, "{}", "Buzz"),
Self::Other(i) => write!(f, "{}", i.to_string())
}
}
}
fn fizz_buzz(i: i32) -> FizzBuzz {
if i % 15 == 0 { FizzBuzz::FizzBuzz }
else if i % 5 == 0 { FizzBuzz::Buzz }
else if i % 3 == 0 { FizzBuzz::Fizz }
else { FizzBuzz::Other(i) }
}
fn main() {
for i in 1..101 {
println!("{}", fizz_buzz(i));
}
}

You are trying to return a reference to a value that only exists on the stack frame, a frame that goes away when you exit the function. This fixes your problem:
fn main() {
fn fizz_buzz(i: i32) -> String {
if i % 15 == 0 {
"FizzBuzz".to_string()
} else if i % 5 == 0 {
"Buzz".to_string()
} else if i % 3 == 0 {
"Fizz".to_string()
} else {
i.to_string()
}
}
for i in 1..101 {
println!("{}" , fizz_buzz(i));
}
}
The key learning is that a String is a string that exists on the heap, and not the stack. The only way to create a dynamic string (such as you do when you cast the i32 to a string) is to put it on the stack. Thus, you have to change your method signature.
(I like Adam Smith's answer better, though! It makes it clear how Rust's notion of lifetimes affects this.)

Related

How to return the maximum over an Iterator of Results?

Minimal example of the structure of my code (playground link):
struct Error;
fn answer() -> Result<Option<i64>, Error> {
(0..100_i64)
.map(|i| -> Result<Option<i64>, Error> {
let candidate = i * 7;
if candidate <= 42 {
Ok(Some(candidate))
} else if candidate == 666 {
Err(Error)
} else {
Ok(None)
}
})
.max()
}
The goal is to take the maximum over the i64 values, returning Ok(None) if none of the Options contained a value, and immediately returning Err(Error) if any of the values were Err(Error).
Of course this doesn't compile as is, because we can't take the max() over an iterable of Results.
With a plain for loop, this would be possible (but inelegant):
fn answer() -> Result<Option<i64>, Error> {
let items = (0..100_i64)
.map(|i| -> Result<Option<i64>, Error> {
let candidate = i * 7;
if candidate <= 42 {
Ok(Some(candidate))
} else if candidate == 666 {
Err(Error)
} else {
Ok(None)
}
});
let mut max = None;
for item in items {
match item {
Ok(candidate) => {
// Conveniently, None < Some(_).
max = std::cmp::max(max, candidate);
}
Err(Error) => {
return Err(Error);
}
}
}
Ok(max)
}
Can it be done using chaining syntax and ? instead?
If you don't want to use an external crate, you can use Iterator's try_fold adaptor, which is only a little more verbose:
struct Error;
fn answer() -> Result<Option<i64>, Error> {
(0..100_i64)
.map(|i| -> Result<Option<i64>, Error> {
let candidate = i * 7;
if candidate <= 42 {
Ok(Some(candidate))
} else if candidate == 666 {
Err(Error)
} else {
Ok(None)
}
})
.try_fold(None, |prev, next| next.map(|ok| std::cmp::max(prev, ok)))
}
Using Itertools::fold_ok from the itertools crate:
fn answer() -> Result<Option<i64>, Error> {
(0..100_i64)
.map(|i| -> Result<Option<i64>, Error> {
let candidate = i * 7;
if candidate <= 42 {
Ok(Some(candidate))
} else if candidate == 666 {
Err(Error)
} else {
Ok(None)
}
})
.fold_ok(None, std::cmp::max) // Conveniently, None < Some(_)
}
I guess that the very existence of this function means that we'd need a Result-aware max function, like max_ok, in order to do this more cleanly.

Borrow inside a loop

I'm trying to learn Rust after many years of C++. I have a situation where the compiler is complaining about a borrow, and it doesn't seem to matter whether it is mutable or immutable. I don't seem to be able to use self as a parameter inside a loop that start with: for item in self.func.drain(..).I've tried calling appropriate() as a function:
Self::appropriate(&self,&item,index)
and I have tried it as a method:
self.appropriate(&item,index)
but I get the same message in either case:
The function or method appropriate() is intended imply examine the relationship among its parameters and return a bool without modifying anything. How can I call either a function or method on self without violating borrowing rules?This program is a learning exercise from exercism.org and doesn't include a main() so it won't run but should almost compile except for the error in question. Here's the code I have:
use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
pub struct Forth {
v: Vec<Value>,
f: HashMap<String,usize>,
s: Vec<Vec<String>>,
func: Vec<String>
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Forth {
pub fn new() -> Forth {
let mut temp: Vec<Vec<String>> = Vec::new();
temp.push(Vec::new());
Forth{v: Vec::<Value>::new(), f: HashMap::new(), s: temp, func: Vec::new()}
}
pub fn stack(&self) -> &[Value] {
&self.v
}
pub fn eval(&mut self, input: &str) -> Result {
self.v.clear();
self.s[0].clear();
let mut count = 0;
{
let temp: Vec<&str> = input.split(' ').collect();
let n = temp.len() as i32;
for x in 0..n as usize {
self.s[0].push(String::from(temp[x]));
}
}
let mut collecting = false;
let mut xlist: Vec<(usize,usize)> = Vec::new();
let mut sx: usize = 0;
let mut z: i32 = -1;
let mut x: usize;
let mut n: usize = self.s[0].len();
loop {
count += 1;
if count > 20 {break;}
z += 1;
x = z as usize;
if x >= n {break;}
z = x as i32;
let word = &self.s[sx][x];
if word == ";" {
if collecting {
collecting = false;
let index: usize = self.s.len();
self.s.push(Vec::<String>::new());
for item in self.func.drain(..) {
if self.s[index].len() > 0 &&
Self::appropriate(&self,&item,index)
{
let sx = *self.f.get(&self.s[index][0]).unwrap();
let n = self.s[sx].len();
for x in 1..n as usize {
let symbol = self.s[sx][x].clone();
self.s[index].push(symbol);
}
}
else {
self.s[index].push(item);
}
}
self.f.insert(self.s[index][0].clone(), index);
self.func.clear();
continue;
}
if 0 < xlist.len() {
(x, n) = xlist.pop().unwrap();
continue;
}
return Err(Error::InvalidWord);
}
if collecting {
self.func.push(String::from(word));
continue;
}
if Self::is_op(word) {
if self.v.len() < 2 {
return Err(Error::StackUnderflow);
}
let b = self.v.pop().unwrap();
let a = self.v.pop().unwrap();
let c = match word.as_str() {
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => {if b == 0 {return Err(Error::DivisionByZero);} a / b},
_ => 0
};
self.v.push(c);
continue;
}
match word.parse::<Value>() {
Ok(value) => { self.v.push(value); continue;},
_ => {}
}
if word == ":" {
collecting = true;
self.func.clear();
continue;
}
if word == "drop" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
self.v.pop();
continue;
}
if word == "dup" {
if self.v.len() < 1 {
return Err(Error::StackUnderflow);
}
let temp = self.v[self.v.len() - 1];
self.v.push(temp);
continue;
}
if !self.f.contains_key(word) {
return Err(Error::UnknownWord);
}
xlist.push((sx,n));
sx = *self.f.get(word).unwrap();
n = self.s[sx].len();
z = 0;
}
Ok(())
}
fn is_op(input: &str) -> bool {
match input {"+"|"-"|"*"|"/" => true, _ => false}
}
fn appropriate(&self, item:&str, index:usize) -> bool
{
false
}
fn prev_def_is_short(&self, index: usize) -> bool {
if index >= self.s.len() {
false
}
else {
if let Some(&sx) = self.f.get(&self.func[0]) {
self.s[sx].len() == 2
}
else {
false
}
}
}
}
The error message relates to the call to appropriate(). I haven't even written the body of that function yet; I'd like to get the parameters right first. The compiler's complaint is:
As a subroutine call
error[E0502]: cannot borrow `self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:47
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | Self::appropriate(&self,&item,index)
| ^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
as a method call
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:85:29
|
81 | for item in self.func.drain(..) {
| -------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
85 | self.appropriate(&item,index)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
Is there any canonical way to deal with this situation?
The problem is that self.func.drain() will consume the elements contained in self.func, thus an exclusive (&mut) access is needed on self.func for the entire for loop.
If during the iteration you need to pass a reference to self globally, then its func member is potentially accessible while the loop holds an exclusive access to it: Rust forbids that.
Since you use drain() in order to consume all the elements inside self.func, I suggest you swap this vector with an empty one just before the loop, then iterate on this other vector that is not anymore part of self.
No copy of the content of the vector is involved here; swap() only deals with pointers.
Here is an over-simplified version of your code, adapted consequently.
struct Forth {
func: Vec<String>,
}
impl Forth {
fn eval(&mut self) {
/*
for item in self.func.drain(..) {
self.appropriate(&self);
}
*/
let mut func = Vec::new();
std::mem::swap(&mut self.func, &mut func);
for item in func.drain(..) {
let b = self.appropriate();
println!("{:?} {:?}", item, b);
}
}
fn appropriate(&self) -> bool {
false
}
}
fn main() {
let mut f = Forth {
func: vec!["aaa".into(), "bbb".into()],
};
f.eval();
}

Temporary value dropped while borrowed while pushing elements into a Vec

I'm trying to solve the RPN calculator exercise at exercism but stumbled upon this temporary value dropped while borrowed error that I can't seem to work out.
Here's my code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(&result.clone());
}
}
}
if stack.len() != 1 {
None
} else {
Some(*stack.pop().unwrap())
}
}
And the error I get:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:32:29
|
32 | stack.push(&result.clone());
| ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
...
36 | if stack.len() != 1 {
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
If I understand correctly, the variable result is no loger live outside of the for loop (outside of the operator match branch indeed), that's why I cloned it, but it still gives me the same error.
How can I make a copy of the result which is owned by the stack Vec (if that's what I should do)?
Just for reference, and in case anybody fins this useful, this is the final solution taking into account all the help received:
use crate::CalculatorInput::{Add,Subtract,Multiply,Divide,Value};
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
Value(value) => {
stack.push(*value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second: i32 = stack.pop().unwrap();
let first: i32 = stack.pop().unwrap();
let result: i32 = match operator {
Add => first + second,
Subtract => first - second,
Multiply => first * second,
Divide => first / second,
Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
stack.pop()
}
}
No need to clone, because i32 implements the Copy trait.
The problem was that my vec was receiving an &i32 instead of i32, and thus rust infered it to be a Vec<&i32>.
The error is because Rust did not infer the type you expected.
In your code, the type of value is inferred to be &i32 because input is a reference of a element in inputs, and you push a value later, therefore the type of stack is inferred to be Vec<&i32>.
A best fix is to explicitly specify the type of stack:
let mut stack: Vec<i32> = Vec::new();
And because i32 has implemented Copy trait, you should never need to clone a i32 value, if it is a reference, just dereference it.
Fixed code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(*value);
}
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
}
}
You have the same behavior with this simple exemple
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(&a.clone());
//-------- ^
println!("{:?}", stack);
}
and the good way is to not borrow when clone.
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(a.clone());
//-------- ^
println!("{:?}", stack);
}
The variable should be used like this stack.push(result.clone()); and change code like this
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
//---------------- ^
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value.clone());
//----------------- ^
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result.clone());
//-^
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
//------- ^
}
}

Error says value moved in previous in iteration of loop, but this doesn't seem true

As seen in the code below, each iteration of the loop defines its own instance of Foo, so I don't see how it could be "moved" in a "previous iteration of loop" when there is a new Foo per loop.
How do I make the error go away?
fn main() {
for i in 0..2 {
let vector: Foo;
// ------ move occurs because `vector` has type `Foo`, which does not implement the `Copy` trait
if i == 0 {
vector = Foo::Bar(vec![1_f32]);
} else if i == 1 {
vector = Foo::Baz(vec![1_u16]);
}
// - value moved here, in previous iteration of loop
println!("{}", vector.len());
// ^^^^^^ value used here after move
}
}
enum Foo {
Bar(Vec<f32>),
Baz(Vec<u16>)
}
impl Foo {
pub fn len(self) -> usize {
match self {
Foo::Bar(vector) => vector.len(),
Foo::Baz(vector) => vector.len(),
#[allow(unreachable_patterns)]
_ => unreachable!()
}
}
}
Your if-else chain is not exhaustive:
fn main() {
for i in 0..2 {
let vector: Foo;
if i == 0 {
vector = Foo::Bar(vec![1_f32]);
} else if i == 1 {
vector = Foo::Baz(vec![1_u16]);
}
// What should happen if `i` is not 0 or 1 ?
// Then the app will try to use an uninitialized variable
// The compiler cannot figure out that it is impossible
// with the current input
println!("{}", vector.len());
}
}
So you have to add an else statement for the case when i is not 0 or 1:
fn main() {
for i in 0..2 {
let vector: Foo;
if i == 0 {
vector = Foo::Bar(vec![1_f32]);
} else if i == 1 {
vector = Foo::Baz(vec![1_u16]);
} else {
unreachable!();
}
println!("{}", vector.len());
}
}
Or better use a match statement (as in your own answer) because it's much cleaner and easier to read:
fn main() {
for i in 0..2 {
let vector: Foo = match i {
0 => Foo::Bar(vec![1_f32]),
1 => Foo::Baz(vec![1_u16]),
_ => unreachable!()
};
println!("{}", vector.len());
}
}
Relevant issue (thanks #nneonneo): https://github.com/rust-lang/rust/issues/72649
By using a match statement I managed to make the errors go away. I don't know why this works and the previous code didn't:
fn main() {
for i in 0..2 {
let vector: Foo = match i {
0 => Foo::Bar(vec![1_f32]),
1 => Foo::Baz(vec![1_u16]),
_ => unreachable!()
};
println!("{}", vector.len());
}
}

How do I access T in an Option<T> without causing a move?

I'm working on an insert function in a binary search tree implementation. Here's my code:
pub struct Node {
data: i32,
left: Option<Box<Node>>,
right: Option<Box<Node>>
}
fn insert_at_root(mut root_node: Node, new_node: Node) -> Node { //not reference because root_node will be mutated
if root_node.data > new_node.data { // value less than root
if let Some(left) = root_node.left {
insert_node(*left, new_node); // *left is a way to downcast box, i.e. *left = T from Box<T>
}
else {
root_node.set_left(Some(Box::new(new_node)));
}
}
else if root_node.data < new_node.data {
if let Some(right) = root_node.right {
insert_node(*right, new_node);
}
else {
root_node.set_right(Some(Box::new(new_node)));
}
}
root_node
}
fn insert_node(mut exist_node: Node, new_node: Node) -> () {
if exist_node.data > new_node.data {
if let Some(left) = exist_node.left {
insert_node(*left, new_node);
}
else {
exist_node.set_left(Some(Box::new(new_node)));
}
}
else if exist_node.data < new_node.data {
if let Some(right) = exist_node.right {
insert_node(*right, new_node);
}
else {
exist_node.set_right(Some(Box::new(new_node)));
}
}
}
I have two insert functions so I can preserve the variable with the root node when I call insert_at_node.
My current problem is the line if let Some(left) = root_node.left { (and the line if let Some(right) = root_node.right {) in the insert_at_root function which apparently causes a move. As a result, I can't return root_node at the end of insert_at_node:
error[E0382]: use of moved value: `root_node`
--> src/lib.rs:34:5
|
19 | if let Some(left) = root_node.left {
| ---- value moved here
...
34 | root_node
| ^^^^^^^^^ value used here after partial move
|
= note: move occurs because value has type `std::boxed::Box<Node>`, which does not implement the `Copy` trait
error: aborting due to previous error
The purpose of those lines is to check if the left (or right) child node is not None, basically root_node.left != None.
Is there any way to achieve this without causing a move? Maybe something with an != or == sign.
You're problem is not that you test whether left/right is Some or None. BTW that could be done with the tests .is_some() and .is_none().
The problem you have is that you bind the variable left to the Node that is in the Option. By that you move the ownership of the content of the Option to the left variable.
In general if you don't want to move the ownership, you have to work with references. When ever the variable is inside an Option and you need to look inside it as a reference, you have to convert the type of it from Option<T> to Option<&T>. By than when you look inside the option, it's just a reference, and therefor doesn't move the ownership.
There are two functions available on Option that do this conversion: .as_ref() to convert to an immutable reference, and .as_mut() that converts to a mutable reference. Because you want to modify the content of left you need a mutable reference, so .as_mut() as what you want.
By using .as_mut() the left you get is a reference instead of the variable itself, so no ownership was transferred.
The next problem you get is that you cannot pass a reference into insert_node because the type signature of this function requires to get the variable instead of a reference. By that it would required that you pass the ownership inside this helper function, so it also wouldn't work. So we convert the signature of insert_node to take &mut Box<Node> instead of Node. So again we only take a reference and not the ownership.
pub fn insert_at_root(mut root_node: Node, new_node: Node) -> Node {
//not reference because root_node will be mutated
if root_node.data > new_node.data {
// value less than root
if let Some(left) = root_node.left.as_mut() {
insert_node(&mut *left, new_node);
} else {
root_node.set_left(Some(Box::new(new_node)));
}
} else if root_node.data < new_node.data {
if let Some(right) = root_node.right.as_mut() {
insert_node(&mut *right, new_node);
} else {
root_node.set_right(Some(Box::new(new_node)));
}
}
root_node
}
pub fn insert_node(exist_node: &mut Box<Node>, new_node: Node) -> () {
if exist_node.data > new_node.data {
if let Some(left) = exist_node.left.as_mut() {
insert_node(&mut *left, new_node);
} else {
exist_node.set_left(Some(Box::new(new_node)));
}
} else if exist_node.data < new_node.data {
if let Some(right) = exist_node.right.as_mut() {
insert_node(&mut *right, new_node);
} else {
exist_node.set_right(Some(Box::new(new_node)));
}
}
}

Resources