I want to build a tree using exactly two structs: Node and Tree and then recursively search for a target node from the tree. If a target is found, return true, else return false.
The challenge for me here is how to recursively call the find function, since it is only defined on Tree not Node.
pub struct Node<T> {
value: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}
pub struct Tree<T> {
root: Option<Box<Node<T>>>,
}
impl<T: Ord> Tree<T> {
/// Creates an empty tree
pub fn new() -> Self {
Tree { root: None }
}
// search the tree
pub fn find(&self, key: &T) -> bool {
let root_node = &self.root; // root is Option
match *root_node {
Some(ref node) => {
if node.value == *key {
return true;
}
let target_node = if *key < node.value {
&node.left
} else {
&node.right
};
match *target_node {
Some(sub_node) => sub_node.find(key),
None => {
return false;
}
}
}
None => return false,
}
}
}
fn main() {
let mut mytree: Tree<i32> = Tree::new();
let node1 = Node {
value: 100,
left: None,
right: None,
};
let boxed_node1 = Some(Box::new(node1));
let root = Node {
value: 200,
left: boxed_node1,
right: None,
};
let boxed_root = Some(Box::new(root));
let mytree = Tree { root: boxed_root };
let res = mytree.find(&100);
}
The current code reports the error:
error: no method named `find` found for type `Box<Node<T>>` in the current scope
--> src/main.rs:36:48
|
36 | Some(sub_node) => sub_node.find(key),
| ^^^^
|
= note: the method `find` exists but the following trait bounds were not satisfied: `Node<T> : std::iter::Iterator`
= help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `find`, perhaps you need to implement one of them:
= help: candidate #1: `std::iter::Iterator`
= help: candidate #2: `core::str::StrExt`
I understand that find is only implemented on Tree, so there is an error, but I don't think it is efficient to implement find on both Tree and Node. Any hint to solve this?
You need to move the majority of the implementation to the Node type, then leave only a small shim in Tree:
impl<T: Ord> Tree<T> {
pub fn find(&self, key: &T) -> bool {
self.root.as_ref().map(|n| n.find(key)).unwrap_or(false)
}
}
impl<T: Ord> Node<T> {
// search the tree
pub fn find(&self, key: &T) -> bool {
if self.value == *key {
return true;
}
let target_node = if *key < self.value {
&self.left
} else {
&self.right
};
target_node.as_ref().map(|n| n.find(key)).unwrap_or(false)
}
}
However, I might avoid multiple comparisons by just matching on the result:
pub fn find(&self, key: &T) -> bool {
use ::std::cmp::Ordering::*;
match self.value.cmp(key) {
Equal => true,
Less => self.left.as_ref().map(|n| n.find(key)).unwrap_or(false),
Greater => self.right.as_ref().map(|n| n.find(key)).unwrap_or(false),
}
}
Or
pub fn find(&self, key: &T) -> bool {
use ::std::cmp::Ordering::*;
let child = match self.value.cmp(key) {
Equal => return true,
Less => self.left.as_ref(),
Greater => self.right.as_ref(),
};
child.map(|n| n.find(key)).unwrap_or(false)
}
I found it is hard to understand target_node.as_ref().map(|n| n.find(key)).unwrap_or(false). I just started to learn the iterator. Is that possible to explain the long expression step by step?
Just follow the type signatures of each function:
self is a &Node<T>
&self.left / &self.right / target_node are a &Option<Box<Node<T>>>
Option::as_ref converts an &Option<T> to Option<&T>. Now we have Option<&Box<Node<T>>>.
Option::map applies a function (which may change the contained type) to the option if it is Some, otherwise it leaves it None.
The function we apply is Node::find, which takes a &Node<T> and returns a bool.
Box<T> implements Deref so any methods on T appear on Box<T>.
Automatic dereferencing allows us to treat &Box<T> as Box<T>.
Now we have Option<bool>
Option::unwrap_or returns the contained value if there is one, otherwise the fallback value provided. The final type is bool.
There is no usage of the Iterator trait. Both Iterator and Option have a map method. If you are interested in the fact that they have the same name and do similar things, that [is what people refer to as a monad. Understanding monads is interesting but not required to actually use them.
Implement the find method on Node and create a stub find method for Tree which could look like this:
impl<T: Ord> Tree<T> {
pub fn find(&self, key: &T) -> bool {
match self.root.as_ref() {
None => false,
Some(x) => x.find(key)
}
}
}
Related
Suppose we have a tree:
#[derive(Default, Debug, PartialEq, Eq)]
struct Tree {
children: Vec<Tree>,
}
And we want to build it from a list of bools where true is like an open tag and false is like a close tag in XML. I.e. [true, true, false, true, false, false] is
root -> node -> node
`-> node
We can easily parse this recursively like this:
fn read_tree_recursive<'a>(tags: &mut impl Iterator<Item=&'a bool>) -> Tree {
let mut tree = Tree::default();
while let Some(&tag) = tags.next() {
if tag {
tree.children.push(read_tree_recursive(tags));
} else {
break;
}
}
tree
}
Here is some test code:
fn main() {
assert_eq!(
read_tree_recursive(&mut [true, true, false, true, false, false].iter()),
Tree {
children: vec![
Tree {
children: vec![
Tree::default(),
Tree::default(),
],
}
],
},
);
}
But how do you do this iteratively? In any other language you'd make a stack of pointers on the heap something like this:
fn read_tree_iterative(tags: &[bool]) -> Tree {
let mut root = Tree::default();
let tree_stack: Vec<&mut Tree> = vec![&mut root];
for &tag in tags {
if tag {
tree_stack.last().unwrap().children.push(Tree::default());
tree_stack.push(tree_stack.last().unwrap().children.last_mut().unwrap());
} else {
tree_stack.pop();
}
}
root
}
Unfortunately this doesn't work in Rust because Rust can't know that we're only ever mutating tree_stack.last(). The recursive version uses function calls to enforce that, but obviously it has the downsides that come with recursion.
Is there a good way around this other than resorting to RefCell? Unfortunately Rust doesn't have become so TCO isn't a good option either.
You can simply store owned values in your stack and add them to the children when you pop them from the stack:
fn read_tree_iterative<'a> (tags: &mut impl Iterator<Item=&'a bool>) -> Tree {
let mut stack = Vec::new();
let mut last = Tree::default();
for &tag in tags {
if tag {
stack.push (last);
last = Tree::default();
} else {
let mut parent = stack.pop().unwrap();
parent.children.push (last);
last = parent;
}
}
last
}
Playground
I'm trying to make a Tic-Tac-Toe game with a custom board size. I want this to be very hard to break, so I use recursion to get the board measurements if the input is invalid or an error occurs. However, this doesn't seem very clean to me, and I was wondering if there's a better/more rusty way of achieving the same thing.
Code in main function
let board_size_str = get_board_size_string();
let (x_pos, width, height) = get_board_measurement(&board_size_str);
Functions
fn get_board_size_string() -> String {
println!("Select the size of the board in the following format: 5x5 or 7x7");
println!("The size can be from 3x3 to 30x30");
print!("Size: ");
std::io::stdout().flush().expect("Failed to flush stdout!");
let mut board_size_str = String::new();
std::io::stdin().read_line(&mut board_size_str).expect("Failed to read board size!");
println!();
board_size_str
}
fn get_board_measurement(board_size_str: &str) -> (usize, i64, i64) {
let x_pos = get_x_pos(board_size_str);
let width = get_board_width(board_size_str, x_pos);
let height = get_board_height(board_size_str, x_pos);
(x_pos, width, height)
}
fn get_x_pos(board_size_str: &str) -> usize {
let x_pos_option = board_size_str.chars().position(|c| c == 'x');
match x_pos_option {
Some(x_pos) => x_pos,
None => {
println!("Board size must contain an x!");
let board_size_str = get_board_size_string();
get_x_pos(&board_size_str)
}
}
}
fn get_board_width(board_size_str: &str, x_pos: usize) -> i64 {
let width_result = board_size_str[..x_pos].parse::<i64>();
match width_result {
Ok(width) => width,
Err(_) => {
println!("Invalid board width!");
let board_size_str = get_board_size_string();
get_board_width(&board_size_str, get_x_pos(&board_size_str))
}
}
}
fn get_board_height(board_size_str: &str, x_pos: usize) -> i64 {
let height_result = board_size_str[x_pos + 1..].trim().parse::<i64>();
match height_result {
Ok(height) => height,
Err(_) => {
println!("Invalid board height!");
let board_size_str = get_board_size_string();
get_board_height(&board_size_str, get_x_pos(&board_size_str))
}
}
}
Just use an iterative loop?
fn get_x_pos(board_size_str: &str) -> usize {
loop {
let board_size_str = get_board_size_string();
let x_pos_option = board_size_str.chars().position(|c| c == 'x');
if let Some(x_pos) = x_pos_option {
break x_pos
}
}
}
Though the structure is strange because a correct board size is a correct pattern ( 'x' ) so it's not like splitting that into three unrelated routines makes any sense, even if two of them do delegate the localisation of the x separator.
With your method you can input something like 52xkf, get an error, input 24x36, and I think you'll get a 52x36 board rather than the 24x36 you might expect, which is just odd. Would be a lot easier to just do the entire thing in a single pseudo-step:
fn parse_board_size() -> (usize, usize) {
loop {
let s = get_board_size_string();
let Some((w_s, h_s)) = s.split_once('x') else {
// complain about a missing `x` here
continue;
};
match (w_s.parse(), h_s.parse()) {
(Ok(w), Ok(s)) => {
// can add more validation here,
// or as pattern guards
return (w, s);
}
(Ok(_), Err(h_error)) => {
// h was incorrect
}
(Err(w_error), Ok(_)) => {
// w was incorrect
}
(Err(w_error), Err(h_error)) => {
// both were incorrect
}
}
}
}
Alternatively for the parsing if you don't care about custom-reporting each error case individually you can lean on Option e.g.
fn parse_board_size() -> (usize, usize) {
loop {
let s = get_board_size_string();
let Some((w_s, h_s)) = s.split_once('x') else {
// complain about a missing `x` here
continue;
};
if let Some(r) = w_s.parse().ok().zip(h_s.parse().ok()) {
break r;
}
// report generic parsing error
}
}
I have a function which returns Future. It accepts another function which accepts one argument and returns Future. Second function can be implemented as combinators chain passed into first function. It looks like this:
use bb8::{Pool, RunError};
use bb8_postgres::PostgresConnectionManager;
use tokio_postgres::{error::Error, Client, NoTls};
#[derive(Clone)]
pub struct DataManager(Pool<PostgresConnectionManager<NoTls>>);
impl DataManager {
pub fn new(pool: Pool<PostgresConnectionManager<NoTls>>) -> Self {
Self(pool)
}
pub fn create_user(
&self,
reg_req: UserRequest,
) -> impl Future<Item = User, Error = RunError<Error>> {
let sql = "long and awesome sql";
let query = move |mut conn: Client| { // function which accepts one argument and returns Future
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[®_req.email, ®_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query) // function which returns Future and accepts another function
}
}
But I want to write code of create_user as a struct implementing Future.
struct UserCreator(Pool<PostgresConnectionManager<NoTls>>, UserRequest);
impl UserCreator {
fn new(pool: Pool<PostgresConnectionManager<NoTls>>, reg_req: UserRequest) -> Self {
Self(pool, reg_req)
}
}
How to implement Future for this struct that works as first function? Please help me with an example.
Now I tried to make it like this, but nothing is computed and execution always blocks.
impl Future for UserCreator {
type Item = User;
type Error = RunError<Error>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// Code which which works like `DataManager.create_user`
let sql = "long and awesome sql";
let reg_req = &self.1;
let query = move |mut conn: Client| {
conn.prepare(sql).then(move |r| match r {
Ok(select) => {
let f = conn
.query(&select, &[®_req.email, ®_req.password])
.collect()
.map(|mut rows| {
let row = rows.remove(0);
row.into()
})
.then(move |r| match r {
Ok(v) => Ok((v, conn)),
Err(e) => Err((e, conn)),
});
Either::A(f)
}
Err(e) => Either::B(future::err((e, conn))),
})
};
self.0.run(query).poll()
}
}
I have a recursive Item structure that I am using to implement lists:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
When implementing a function that inserts an element after another one, I found out that the Rust compiler wasn't that happy about my code:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
The errors that I get are pretty obscure for a newbie:
error[E0382]: use of collaterally moved value: `(it as Item::Cons).1`
--> src/main.rs:12:23
|
12 | Item::Cons(a, b) => {
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because the value has type `T`, which does not implement the `Copy` trait
Another similar question suggested to do the unwrapping phase in two steps but it cannot be used here because we need to directly unwrap a two-fields Cons(..) item and not nested items like Option<Box<Whatever>> where the two-phase trick can be applied. Example of what I tried:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(..) => {
let Item::Cons(a, b) = *it;
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
But I get another error:
error[E0005]: refutable pattern in local binding: `Nil` not covered
--> src/main.rs:13:17
|
13 | let Item::Cons(a, b) = *it;
| ^^^^^^^^^^^^^^^^ pattern `Nil` not covered
Though I am pretty sure here that this is exhaustive at this point because we matched a Cons before.
You may be suffering from issue 16223 (see also 22205 which has a closer reproduction), although today's non-lexical lifetimes don't solve this problem. This seems to preclude destructuring multiple things through a Box.
Here's one way to work around it, although it's not the most efficient way as it deallocates and reallocates unnecessarily:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match { *it } {
Item::Nil => Box::new(Item::Nil),
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
Box::new(Item::Cons(a, itm))
}
}
}
fn main() {}
A more verbose way pulls the value out of the Box, manipulates that, and then puts the manipulated value back into the Box. This should have a reduced amount of allocations:
use std::mem;
pub fn add_after<T>(mut item: Box<Item<T>>, val: T) -> Box<Item<T>> {
let unboxed_value = mem::replace(&mut *item, Item::Nil);
match unboxed_value {
Item::Nil => item,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
*item = Item::Cons(a, itm);
item
}
}
}
See also:
Collaterally moved error when deconstructing a Box of pairs
I tried my hands at Rust for the first time today (writing a XML tokenizer), and naturally don’t understand everything:
I have a struct with field that can take an enum value:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
In a impl Tokenizer, I want to match on the current state, and change it in some cases, however this always gives a use of moved value error.
H to access and/or declare the state field so that I can match on it and change its value inside a match branch?
Sorry for the confusion, I meant to change the Tokenizer’s state field, not the state’s String field!
match self.state {
InATag(name) => self.state = Outside,
Outside => ()
}
Without a more concrete example, it is hard to tell whether this would solve your problem, but you can use ref within a match pattern to make a reference to the matched substructure, and you can use ref mut to make that reference mutable.
So, in your example:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t.state {
InATag(ref mut _s) => { *_s = ~"bar"; }
Outside => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
or if you need to match other parts of the Tokenizer state, this works too:
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match t {
Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
Note that when doing this sort of code, it can be pretty easy to inadvertently run into borrow-check violations due to aliasing. For example, here is a relatively small change to the second example above that won't compile:
fn main() {
let mut t = Tokenizer { state: InATag(~"foo") };
match &t {
&Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
&Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello World: %?", t));
}
causes the following message from rustc:
/tmp/m.rs:7:35: 7:46 error: illegal borrow: creating mutable alias to enum content
/tmp/m.rs:7 &Tokenizer { state: InATag(ref mut _s) } => { *_s = ~"bar"; }
^~~~~~~~~~~
error: aborting due to previous error
because you do not want an outstanding borrow &t while you are also creating mutable aliases to the internals of t
Okay, with the clarified variant of the question, here is my revised answer:
enum State { Outside, InATag(~str) }
struct Tokenizer { state: State }
impl Tokenizer {
fn toggle(&mut self) {
match self {
&Tokenizer { state: InATag(*) } => { self.state = Outside }
&Tokenizer { state: Outside } => { self.state = InATag(~"baz") }
}
}
}
fn main() {
let mut t1 = Tokenizer { state: InATag(~"foo") };
match t1 {
Tokenizer { state: InATag(*) } => { t1.state = Outside }
Tokenizer { state: Outside } => { /* impossible */ }
}
io::println(fmt!("Hello t1: %?", t1));
let mut t2 = Tokenizer { state: InATag(~"bar") };
t2.toggle();
io::println(fmt!("World t2: %?", t2));
}
I admit, I actually did not expect it to be as easy as the above, and I can easily believe that small changes to the above code could cause it to start failing to borrow-check. But without a more fleshed out example from the asker, it is hard to tell whether the above code would suit his purposes or not.
Oh, here's the output when I compile and run the code:
% rustc /tmp/m.rs
warning: no debug symbols in executable (-arch x86_64)
% /tmp/m
Hello t1: {state: Outside}
World t2: {state: Outside}
%