I have some code that looks like this:
trait Stack {
fn top(&mut self) -> Option<f64>;
}
impl Stack for Vec<f64> {
fn top(&mut self) -> Option<f64> {
match self.pop() {
None => None,
Some(v) => {
self.push(v);
Some(v)
}
}
}
}
fn main() {
let mut stack: Vec<f64> = Vec::new();
stack.push(5.3);
stack.push(2.3);
stack.push(1.3);
match stack.top() {
Some(v) => println!("Top of the stack: {}", v),
None => println!("The stack is empty"),
}
}
Right now, the top() method is modifying self, but I think that this should not be necessary. The obvious way to do it didn't really work:
fn top(&mut self) -> Option<f64> {
match self.len() {
0 => None,
n => self[n - 1],
}
}
I've toyed around a bit with converting usize to i32 and back, but none of what I'm writing looks as short and readable as I think it should.
You can use slice::last:
fn top(&mut self) -> Option<f64> {
self.last().copied()
}
Option::copied (and Option::cloned) can be used to convert from an Option<&f64> to an Option<f64>, matching the desired function signature.
You can also remove the mut from both the implementation and the trait definition.
And just after posting the question, the answer appears to be obvious:
fn top (&mut self) -> Option<&f64> {
match self.len() {
0 => None,
n => Some(&self[n-1])
}
}
I.e. the usize was never the problem - the return type of top() was.
Related
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
}
}
This question already has answers here:
Conditionally iterate over one of several possible iterators
(4 answers)
Closed 2 years ago.
I want have something like below
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> impl IntoIterator<Item = i32> {
match self {
DiffStruct::V(vec) => vec.iter().into_iter(),
DiffStruct::M(map) => map.values().into_iter(),
}
}
}
fn main() {
let v: Vec<_> = DiffStruct::V(vec![1,2,3]).to_iter().collect();
}
playground
So that I can minimize the collect behavior of my code for best performance, but it does not compile, any workaround to achieve this?
Assuming you want to take ownership of DiffStruct and not just borrow it when you collect its values:
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> Box<dyn Iterator<Item = i32>> {
match self {
DiffStruct::V(vec) => Box::new(vec.into_iter()),
DiffStruct::M(map) => Box::new(map.into_iter().map(|(_, v)| v)),
}
}
}
fn main() {
let vec_values = vec![1, 2, 3];
let mut map_values = HashMap::new();
map_values.insert(1, 1);
map_values.insert(2, 2);
map_values.insert(3, 3);
let ds_vec = DiffStruct::V(vec_values);
let ds_map = DiffStruct::M(map_values);
let collected_from_vec: Vec<_> = ds_vec.to_iter().collect();
let collected_from_map: Vec<_> = ds_map.to_iter().collect();
}
playground
See also
Conditionally iterate over one of several possible iterators
What is the correct way to return an Iterator?
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 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)
}
}
}
I have a simple linked list type and an implementation of Clone for
it:
#[deriving(Show)]
enum List {
Cons(int, Box<List>),
Nil,
}
impl Clone for List {
fn clone(&self) -> List {
match *self {
Cons(val, ref rest) => Cons(val, rest.clone()),
Nil => Nil,
}
}
}
It works as expected. But if I make my own MyClone trait with
the same signature
as that of Clone, I get an error:
trait MyClone {
fn my_clone(&self) -> Self;
}
impl MyClone for List {
fn my_clone(&self) -> List {
match *self {
Cons(val, ref rest) => Cons(val, rest.my_clone()),
Nil => Nil,
}
}
}
.../src/main.rs:23:46: 23:61 error: mismatched types: expected `Box<List>`, found `List` (expected box, found enum List)
.../src/main.rs:23 Cons(val, ref rest) => Cons(val, rest.my_clone()),
It works fine if I change it to box rest.my_clone(), but I don't
understand why. The MyClone and Clone traits are the same, so it
seems to me they would accept the same implementation.
(I'm compiling with rustc 0.12.0-nightly (72841b128 2014-09-21 20:00:29 +0000).)
This is because rust also has an implementation of Clone for Box<T>. If you implement MyClone for it, it will owrk at expected.
#[deriving(Show)]
enum List {
Cons(int, Box<List>),
Nil,
}
trait MyClone {
fn my_clone(&self) -> Self;
}
impl<T: MyClone> MyClone for Box<T> {
fn my_clone(&self) -> Box<T> {
self.my_clone()
}
}
impl MyClone for List {
fn my_clone(&self) -> List {
match *self {
Cons(val, ref rest) => Cons(val, rest.my_clone()),
Nil => Nil,
}
}
}