Rust enum implement += 1 - rust

I try to write Minesweeper
I have enum with status of cell and trying to write function to recognize how much mines around it.
enum CellStatus {
CLOSED,
MINED,
FLAGED,
OPENED,
ONE,
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT
}
if mine_area[i+1][j+1] == CellStatus::MINED {
mine_area[i][j] += 1;
}
This is what compiler advice me:
error[E0368]: binary assignment operation `+=` cannot be applied to type `CellStatus`
--> src/main.rs:25:9
|
25 | mine_area[i][j] += 1;
| ---------------^^^^^
| |
| cannot use `+=` on type `CellStatus`
|
note: an implementation of `AddAssign<_>` might be missing for `CellStatus`
--> src/main.rs:126:1
|
126 | enum CellStatus {
| ^^^^^^^^^^^^^^^ must implement `AddAssign<_>`
note: the following trait must be implemented
On offical AddAssign it is example for Point, and it struct not enum.
BrownieInMotion advised me to use u8 in Opened, it's really helpful, but not a solution to a problem.

What about using an enum like this instead?
enum Status {
Closed,
Flagged,
Mined,
Opened(u8),
}
However, I am a bit confused about how the mine state is held. I think it makes sense to use this when representing how mines should be displayed, but I see that you are also using this enum to hold the board state itself.
if mine_area[i+1][j+1] == CellStatus::MINED
I don't think this check makes sense because this enum is not suited for representing the state of the board; it's better for representing how the board should be drawn.
For example, a cell with a mine can be flagged or not flagged, but the enum can only represent one of these traits at a time.

Here is how to do it correct:
impl AddAssign for Status {
fn add_assign(&mut self, other: Self) {
*self = match *self {
Status::Opened(count) => match other {
Status::Opened(count2) => Status::Opened(count + count2),
_ => other,
},
_ => other
}
}
}
My final implementation is:
use std::ops::AddAssign;
fn main() {
let width:u16 = 5;
let heigh:u16 = 5;
let mut game_area = vec![vec![Status::Closed; width.into()]; heigh.into()];
game_area[1][1] = Status::Opened(0);
game_area[1][1] += Status::Opened(1);
game_area[1][1] += Status::Opened(1);
game_area[1][1] += Status::Opened(1);
println!("{}", game_area[1][1].as_str());
}
#[derive(Clone)]
enum Status {
Closed,
Flagged,
Mined,
Opened(u8),
}
const MINE_CHAR: [&str; 9] = ["🔳", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣"];
impl Status {
pub fn as_str(&self) -> String {
match self {
Status::Mined => "💣".to_string(),
Status::Closed => "⬜".to_string(),
Status::Flagged => "🚩".to_string(),
Status::Opened(i) => MINE_CHAR[*i as usize].to_string()
}}
}
impl AddAssign for Status {
fn add_assign(&mut self, other: Self) {
*self = match *self {
Status::Opened(count) => match other {
Status::Opened(count2) => Status::Opened(count + count2),
_ => other,
},
_ => other
}
}
}

Related

Why can't rust infer types specified after arithmetic operators?

Can anyone tell me why code 1 works but code2 doesn't?
code 1
let guess: u32 = match guess.trim().parse() {
Ok(num) => {num},
Err(e) => {println!("{}",e);0},
};
code 2
let guess: u32 = match guess.trim().parse() {
Ok(num) => {num * 2},
Err(e) => {println!("{}",e);0},
};
error
error[E0282]: type annotations needed
--> src/main.rs:18:16
|
18 | Ok(num) => {num * 2},
| ^^^ cannot infer type
|
help: consider specifying the type argument in the method call
|
17 | let guess: u32 = match guess.trim().parse::<F>() {
| +++++
You could create a ambiguous type easily in this way. The Result of a operator is not unique. Consider if this existed somewhere in your code.
struct A;
// Allow this struct to be used in Parse
impl FromStr for A {
... // implementation of FromStr
}
// Allow this struct to be used in add
impl Add<u32> for A {
type Output = u32;
// implementation of Add
}
fn main() {
let k:u32 = "".parse().unwrap() + 5
}
What variant of parse should be used? u32 or A? There is no way to tell, both would be valid. A could be defined in some external crate and thus modify code based on a situation that's hard to control.
For this reason, rust can't infer types past operators.
You can easily clarify the variant used with the turbofish (::<>) operator:
fn main() {
let k:u32 = "".parse::<u32>().unwrap() + 5
}

Borrowing errors whilst mutating in for loop

I am having issues with the borrow checker and temporary values in rust.
I'm hoping to find a solution to this specific problem as well as better learn how to handle this kind of situation in the future. I originally started off with a for_each but ran into issues terminating early.
I considered moving the logic of check_foo into update_foo, however this wouldn't work well for my real world solution; the MRE focuses on the compilation issues vs what I'm trying to achieve in the whole program.
Edit: Is there a way for me to achieve this in a purely functional approach?
I want to iterate over a range of numbers, updating a Vec<Foo> and potentially returning early with a value. Below is a minimal reproducible example of my code with the same errors:
I tried tried implementing as:
fn run<'a>(mut foos: Vec<Foo>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &mut foos {
update_foo(foo);
let checked_foo = check_foo(&foo);
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
/* `fn update_foo` and `fn check_foo` definitions same as below */
but this resulted in:
21 | for foo in &mut foos {
| ^^^^^^^^^ `foos` was mutably borrowed here in the previous iteration of the loop
To overcome this I added the use of Rc and RefCell to allow me to iterate over a reference whilst still being able to mutate:
#[derive(Clone, Debug, PartialEq)]
pub struct Foo {
updated: bool,
}
fn run<'a>(foos: Vec<Rc<RefCell<Foo>>>) -> Vec<&'a u32> {
let mut bar: Vec<&u32> = vec![];
for num in 0..10 {
for foo in &foos {
update_foo(&mut foo.borrow_mut());
let checked_foo = check_foo(&foo.borrow());
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
fn update_foo(foo: &mut Foo) {
foo.updated = true
}
fn check_foo(foo: &Foo) -> Vec<&u32> {
if foo.updated {
vec![&0, &1, &2]
} else {
vec![]
}
}
which results in:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:33:5
|
26 | let checked_foo = check_foo(&foo.borrow());
| ------------ temporary value created here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
error[E0515]: cannot return value referencing function parameter `foos`
--> src/main.rs:33:5
|
23 | for foo in &foos {
| ----- `foos` is borrowed here
...
33 | bar
| ^^^ returns a value referencing data owned by the current function
For more information about this error, try `rustc --explain E0515`.
I'm not entirely sure what you plan to do with this, but it seems to me like a few of the references you're using should be owned. Here's what I came up with.
#[derive(Clone, Debug, PartialEq)]
pub struct Foo {
updated: bool,
}
fn run(foos: &mut Vec<Foo>) -> Vec<u32> {
let mut bar: Vec<u32> = vec![];
for num in 0..10 {
for foo in foos.iter_mut() {
update_foo(foo);
let checked_foo = check_foo(&foo);
if checked_foo.is_empty() {
bar = checked_foo;
break;
}
}
}
bar
}
fn update_foo(foo: &mut Foo) {
foo.updated = true
}
fn check_foo(foo: &Foo) -> Vec<u32> {
if foo.updated {
vec![0, 1, 2]
} else {
vec![]
}
}
References should be used when you expect some other struct to own the objects you are referring to, but here you're constructing new vectors with new data, so you should keep the elements owned.

Create an iterator and put it into a new struct without bothering the borrow-checker [duplicate]

This question already has answers here:
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 3 years ago.
I am trying to create a lexical analyzer which uses itertools::PutBack to make an iterator over the characters in a String. I intend to store the pushback iterator in a struct and delegate methods to it so that I can categorize the characters by an enum, which will then be passed to a state machine at the core of the lexical analyzer (not yet written).
The borrow-checker is not happy with me. Method ParserEventIterator::new near the bottom of the listing causes the error. How do I define the lifetimes or borrowing so that I can get this to compile? Or what Rustic data structure design should I use in its stead?
Ultimately, I would like this to implement the appropriate traits to become a proper iterator. (Newbie to Rust. Prior to this, I have programmed in 28 languages, but this one has me stumped.)
Here is a code sample:
extern crate itertools;
use itertools::put_back;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
pub enum ParserEvent {
Letter(char),
Digit(char),
Other(char),
}
impl ParserEvent {
fn new(c: char) -> ParserEvent {
match c {
'a'...'z' | 'A'...'Z' => ParserEvent::Letter(c),
'0'...'9' => ParserEvent::Digit(c),
_ => ParserEvent::Other(c),
}
}
}
impl Display for ParserEvent {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut _ctos = |c: char| write!(f, "{}", c.to_string());
match self {
ParserEvent::Letter(letter) => _ctos(*letter),
ParserEvent::Digit(digit) => _ctos(*digit),
ParserEvent::Other(o) => _ctos(*o),
}
}
}
// ParserEventIterator
// Elements ('e) must have lifetime longer than the iterator ('i).
pub struct ParserEventIterator<'i, 'e: 'i> {
char_iter: &'i mut itertools::PutBack<std::str::Chars<'e>>,
}
impl<'i, 'e: 'i> ParserEventIterator<'i, 'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'i, 'e> {
// THIS NEXT LINE IS THE LINE WITH THE PROBLEM!!!
ParserEventIterator {
char_iter: &mut put_back(s.chars()),
}
}
fn put_back(&mut self, e: ParserEvent) -> () {
if let Some(c) = e.to_string().chars().next() {
self.char_iter.put_back(c);
}
}
}
impl<'i, 'e: 'i> Iterator for ParserEventIterator<'i, 'e> {
type Item = ParserEvent;
fn next(&mut self) -> Option<ParserEvent> {
match self.char_iter.next() {
Some(c) => Some(ParserEvent::new(c)),
None => None,
}
}
}
fn main() {
let mut _i = ParserEventIterator::new(&String::from("Hello World"));
}
On the Rust Playground
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:43:9
|
43 | / ParserEventIterator {
44 | | char_iter: &mut put_back(s.chars()),
| | ------------------- temporary value created here
45 | | }
| |_________^ returns a value referencing data owned by the current function
Well, the compiler is almost telling you the solution by reflecting to the obvious problem: you can't have a borrow which doesn't live long enough, i.e. the borrow would point to a nonexistent location after the stack memory of the function has been destroyed.
This would happen because the borrow is referencing an object (in this case an itertools::struct::PutBack instance) that has been newly created within the function body. This instance gets destroyed at the end of the function along with all the references to it. So the compiler is preventing you to have a so called dangling pointer.
Thus, instead of borrowing you should move the PutBack instance into your struct:
// ...
pub struct ParserEventIterator<'e> {
char_iter: itertools::PutBack<std::str::Chars<'e>>
}
impl<'e> ParserEventIterator<'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'e> {
ParserEventIterator { char_iter: put_back(s.chars()) }
}
// ...
}

How do I use match to modify a mutable variable in a way that is guaranteed to be non-exhaustive and not require clone?

When using a match to modify a mutable variable, I haven't found a way to use match in a way that is guaranteed to be non-exhaustive and not requiring clone.
struct Stuff {
num: u32,
thing: bool,
}
enum Bar {
Nothing,
SomeStuff(Stuff),
AlsoNothing,
}
fn main() {
let mut things = vec![Bar::SomeStuff(Stuff {
num: 2,
thing: false,
})];
for x in things.iter_mut() {
*x = match *x {
Bar::Nothing => Bar::AlsoNothing,
Bar::AlsoNothing => Bar::SomeStuff(Stuff {
num: 3,
thing: true,
}),
Bar::SomeStuff(thing) => panic!("not sure"),
}
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:19:20
|
19 | *x = match *x {
| ^^ cannot move out of borrowed content
...
25 | Bar::SomeStuff(thing) => panic!("not sure"),
| ----- hint: to prevent move, use `ref thing` or `ref mut thing`
My intent is to write Bar::SomeStuff(thing) => Bar::SomeStuff(thing) and effectively leave it unchanged, but I cannot move through with a borrow or a reference.
Bar::SomeStuff(thing.clone()) could work, but copying a big struct could be very expensive.
Removing the *x = and changing to () could also work, but I am only returning a Bar enum so having the compiler check the return type is something I hope to keep.
If you want to pass a value unchanged, just capture the match with a variable and pass that back, e.g.
fn foo(a: u32) -> u32 {
match a {
0 => 1,
1 => 2,
e => e,
}
}
In your case, I would move the variable assignment into the match arms
for x in things.iter_mut() {
match x {
Bar::Nothing => *x = Bar::AlsoNothing,
Bar::AlsoNothing => *x = Bar::SomeStuff(Stuff { num: 3, thing: true }),
_ => {},
}
}

How do you convert an instance of generic T into a concrete instance in Rust?

I'm trying to implement this pattern:
use std::any::Any;
use std::fmt::Debug;
trait CommandHandler<TCommand> {
fn execute(&self, data: TCommand);
}
#[derive(Debug)]
struct FooCommand {}
struct FooCommandHandler {}
impl CommandHandler<FooCommand> for FooCommandHandler {
fn execute(&self, data: FooCommand) {
println!("Foo");
}
}
#[derive(Debug)]
struct BarCommand {}
struct BarCommandHandler {}
impl CommandHandler<BarCommand> for BarCommandHandler {
fn execute(&self, data: BarCommand) {
println!("Bar");
}
}
fn execute<T>(command: T)
where
T: Any + Debug,
{
println!("Command: {:?}", command);
match (&command as &Any).downcast_ref::<FooCommand>() {
Some(c) => (FooCommandHandler {}).execute(c),
None => {}
};
match (&command as &Any).downcast_ref::<BarCommand>() {
Some(c) => (BarCommandHandler {}).execute(c),
None => {}
};
}
fn main() {
(FooCommandHandler {}).execute(FooCommand {});
(BarCommandHandler {}).execute(BarCommand {});
execute(FooCommand {});
execute(BarCommand {});
}
This doesn't work:
error[E0308]: mismatched types
--> src/main.rs:37:51
|
37 | Some(c) => (FooCommandHandler {}).execute(c),
| ^ expected struct `FooCommand`, found &FooCommand
|
= note: expected type `FooCommand`
found type `&FooCommand`
error[E0308]: mismatched types
--> src/main.rs:41:51
|
41 | Some(c) => (BarCommandHandler {}).execute(c),
| ^ expected struct `BarCommand`, found &BarCommand
|
= note: expected type `BarCommand`
found type `&BarCommand`
How can I implement the execute() method in a way that preserves the following requirements:
The type XCommand should be totally naive of the XCommandHandler's that execute it.
Multiple implementations of CommandHandler<X> may exist.
The command handler receives (and consumes) the concrete command instance, not a reference to it (making duplicate dispatch of commands impossible).
In essence, I have a generic function fn foo<T>(v: T) and a I wish to dispatch to a number of concrete functions fn foo1(v: Foo), fn foo2(v: Bar); how do I do that?
Is transmute the only option?
Note that this is distinct from what Any::downcast_ref does, which is return an &Foo, not Foo from the generic value v.
You need to go via Box, like so:
fn execute<T>(command: T)
where
T: Any + Debug,
{
println!("Command: {:?}", command);
let any: Box<Any> = Box::new(command);
let any = match any.downcast() {
Ok(c) => return (FooCommandHandler {}).execute(*c),
Err(any) => any,
};
let any = match any.downcast() {
Ok(c) => return (BarCommandHandler {}).execute(*c),
Err(any) => any,
};
let _ = any; // avoid unused variable error
panic!("could not downcast command");
}
"But I don't wanna use a Box!"
Just use Box.
"But it's an allocation! I've measured the above code and proven beyond a shadow of a doubt that it's a bottleneck!"
What? Really?
"You can't prove otherwise."
Oh fine. But I do not guarantee that this will work in all cases. This is treading into "blow yourself up" territory. Do not do this unless you know you need to:
fn execute<T>(command: T)
where
T: Any + Debug,
{
use std::any::TypeId;
use std::mem;
println!("Command: {:?}", command);
macro_rules! do_cast {
($t:ty, $h:expr) => {
if TypeId::of::<T>() == TypeId::of::<$t>() {
let casted: $t = mem::transmute_copy(&command);
mem::forget(command); // we CANNOT let command drop.
$h.execute(casted);
return;
}
};
}
unsafe {
do_cast!(FooCommand, FooCommandHandler {});
do_cast!(BarCommand, BarCommandHandler {});
}
panic!("could not downcast command");
}
Just as a quick summary of the accepted answer:
Where &Any only has:
pub fn downcast_ref<T>(&self) -> Option<&T> where T: Any
Box<Any> implements:
pub fn downcast<T>(self) -> Result<Box<T>, Box<Any + 'static>> where T: Any
However, for complicated reasons, the documentation is on Box not on Any.

Resources