flat_map on Chars causes borrow checker error - iterator

I'm trying to generate a sequence like this: 1,2,3,4,5,6,7,8,9,1,0,1,1,1,2...
fn main() {
let iter = (1..).flat_map(|j| j.to_string().chars());
for i in iter {
println!("{}", i);
}
}
This does not work, because j.to_string() goes out of scope I believe (but why?)
p040.rs:2:35: 2:48 error: borrowed value does not live long enough
p040.rs:2 let iter = (1..).flat_map(|j| j.to_string().chars());
^~~~~~~~~~~~~
p040.rs:2:58: 6:2 note: reference must be valid for the block suffix following statement 0 at 2:57...
p040.rs:2 let iter = (1..).flat_map(|j| j.to_string().chars());
p040.rs:3 for i in iter {
p040.rs:4 println!("{}", i);
p040.rs:5 }
p040.rs:6 }
p040.rs:2:35: 2:56 note: ...but borrowed value is only valid for the block at 2:34
p040.rs:2 let iter = (1..).flat_map(|j| j.to_string().chars());
^~~~~~~~~~~~~~~~~~~~~
How could I solve this compiler error?

Iterators are lazy and can only live as long as their iteratee lives. j.to_string() is temporary and only lives inside the closure, hence the closure cannot return j.to_string().chars().
A simple solution would be to collect the characters before returning:
fn main() {
let iter = (1..).flat_map(|j| j.to_string().chars().collect::<Vec<_>>());
for i in iter {
println!("{}", i);
}
}

One problem with the solution that uses collect is that it keeps allocating strings and vectors. If you need a implementation that does the minimum allocation, you can implement your own iterator:
#[derive(Default)]
struct NumChars {
num: usize,
num_str: Vec<u8>,
next_index: usize,
}
impl Iterator for NumChars {
type Item = char;
fn next(&mut self) -> Option<char> {
use std::io::Write;
if self.next_index >= self.num_str.len() {
self.next_index = 0;
self.num += 1;
self.num_str.clear();
write!(&mut self.num_str, "{}", self.num).expect("write failed");
}
let index = self.next_index;
self.next_index += 1;
Some(self.num_str[index] as char)
}
}
fn main() {
assert_eq!(
vec!['1', '2', '3', '4', '5', '6', '7', '8', '9', '1', '0', '1', '1'],
NumChars::default().take(13).collect::<Vec<_>>()
);
}

Related

Is there an alternative to this unsafe code for mutable index rust

I am making a chess game and I'm looking to return a mutable null character from an array of pieces when the index of the array (a Vec2 is out of bounds), the reason I need to do this is that my function for moving the piece needs a mutable reference to the Indexed piece, long story short I ended up needing to create a static NULL_PIECE that I could reference within the function but this is potentially quite dangerous as you'll see from my code
impl Index<IVec2> for Board {
type Output = Piece;
fn index(&self, index : IVec2) -> &Self::Output{
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
&Piece('\0') // this works
} else {
let i : usize = (index.x + WIDTH* index.y).try_into().unwrap();
&self.pieces[i]
}
}
}
impl IndexMut<IVec2> for Board {
fn index_mut(&mut self, index: IVec2) -> &mut Self::Output{
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
// &mut Piece('\0') // this does not work
unsafe {&mut NULL_PIECE} // this works but I don't like it
} else {
let i : usize = (index.x + WIDTH * index.y).try_into().unwrap();
&mut self.pieces[i]
}
}
}
There is a lot of potential for this to cause an error in the event that this mutates to be a piece because of the recursion I've implemented on the piece movement.
You can find the GitHub link here:
https://github.com/LyndonAlcock/chess_test/tree/main/src
Instead of implementing Index you could write it as:
impl Board {
fn get(&self, index: IVec2) -> Option<&Piece> {
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
None
} else {
let i = (index.x + WIDTH* index.y).try_into().ok()?;
Some(&self.pieces[i])
}
}
fn get_mut(&mut self, index: IVec2) -> Option<&mut Piece> {
if (index.abs() != index) || (index.max_element() > WIDTH-1) {
None
} else {
let i = (index.x + WIDTH * index.y).try_into().ok()?;
Some(&mut self.pieces[i])
}
}
}
Index implementations should panic when the index is out of bounds.

elegant way of capturing a reference to an integer variable?

I have this snippet:
let mut animation_index = 0 as usize;
let mut ptr : *mut usize = &mut animation_index as _;
{
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
unsafe {
*ptr += 1;
println!("{}", animation_index);
}
}
})
);
}
Basically it adds a callback such that if and when I press space, the integer variable animation_index goes up by 1. This works, but requires the use of mutable pointers and unsafe, which is very ugly.
I'd like to have the same logic but ideally do it with pure safe rust isntead.
It looks like you are trying to share a mutable value across threads.
Typically, this is done with atomics, Arc<Mutex<T>> or Arc<RwLock<T>>.
use std::synce::{Arc, RwLock};
let mut animation_index = Arc::new(RwLock::new(0usize));
{
// a clone of the counter that can be moved into the callback
let animation_index = animation_index.clone();
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
let index = animation_index.write().unwrap();
*index += 1;
println!("{}", index);
}
})
);
}
With atomics it would look something like this:
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
let mut animation_index = Arc::new(AtomicUsize::new(0));
{
// a clone of the counter that can be moved into the callback
let animation_index = animation_index.clone();
io_context.window().add_key_callback(
Box::new(move |key_states| {
if key_states[KbKey::Space.to_index()] == KeyActionState::Press
{
let index = animation_index.fetch_add(1, Ordering::SeqCst);
println!("{}", index);
}
})
);
}

Index out of bounds while checking if a string is rotated

// This function checks if two string are rotation of itself
//
// #Arguments
//
// 'str1' - a str type reference to store one string to check
// 'str2' - a str type reference to store other string to check
//
// #Return
//
// Return a bool value denoting if the string are rotation of each other
pub fn is_rotation(str1: &str, str2: &str) -> bool {
let len1 = str1.len();
let len2 = str2.len();
let string1: Vec<char> = str1.chars().collect();
let string2: Vec<char> = str2.chars().collect();
if len1 != len2 {
return false;
}
let mut longest_prefix_suffix = vec![0, len1];
let mut prev_len = 0;
let mut i = 1;
while i < len1 {
if string1[i] == string2[prev_len] {
prev_len += 1;
longest_prefix_suffix[i] = prev_len;
i += 1;
} else if prev_len == 0 {
longest_prefix_suffix[i] = 0;
i += 1;
} else {
prev_len = longest_prefix_suffix[prev_len - 1];
}
}
i = 0;
let mut k = longest_prefix_suffix[len1 - 1];
while k < len2 {
if string2[k] != string1[i] {
return false;
}
i += 1;
k += 1;
}
true
}
When I run the code, I receive the following error:
thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 2', src/rotation.rs:29:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
How would I solve this?
It looks like there is a typo for longest_prefix_suffix. I assume you intended to write the following:
let mut longest_prefix_suffix = vec![0; len1];
Note the ; between 0 and len1.
The use of a , created a Vec with two elements.
Alternatively, an easier way might be the following:
fn is_rotation(s1: &str, s2: &str) -> bool {
if s1.len() != s2.len() {
return false;
}
s1.repeat(2).contains(&s2)
}
assert!(is_rotation("hello", "ohell") // true
assert!(is_rotation("hello", "olleh") // false

Return Option inside Loop

The program aims to use a loop to check if the index of a iterator variable meets certain criteria (i.g., index == 3). If find the desired index, return Some(123), else return None.
fn main() {
fn foo() -> Option<i32> {
let mut x = 5;
let mut done = false;
while !done {
x += x - 3;
if x % 5 == 0 {
done = true;
}
for (index, value) in (5..10).enumerate() {
println!("index = {} and value = {}", index, value);
if index == 3 {
return Some(123);
}
}
return None; //capture all other other possibility. So the while loop would surely return either a Some or a None
}
}
}
The compiler gives this error:
error[E0308]: mismatched types
--> <anon>:7:9
|
7 | while !done {
| ^ expected enum `std::option::Option`, found ()
|
= note: expected type `std::option::Option<i32>`
= note: found type `()`
I think the error source might be that a while loop evaluates to a (), thus it would return a () instead of Some(123). I don't know how to return a valid Some type inside a loop.
The value of any while true { ... } expression is always (). So the compiler expects your foo to return an Option<i32> but finds the last value in your foo body is ().
To fix this, you can add a return None outside the original while loop. You can also use the loop construct like this:
fn main() {
// run the code
foo();
fn foo() -> Option<i32> {
let mut x = 5;
loop {
x += x - 3;
for (index, value) in (5..10).enumerate() {
println!("index = {} and value = {}", index, value);
if index == 3 {
return Some(123);
}
}
if x % 5 == 0 {
return None;
}
}
}
}
The behaviour of while true { ... } statements is maybe a bit quirky and there have been a few requests to change it.

is it possible to filter on a vector in-place?

I'd like to remove some elements from a Vec, but vec.iter().filter().collect() creates a new vector with borrowed items.
I'd like to mutate the original Vec without extra memory allocation (and keep memory of removed elements as an extra capacity of the vector).
If you want to remove elements, you can use retain(), which removes elements from the vector if the closure returns false:
let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);
If you want to modify the elements in place, you have to do that in a for x in vec.iter_mut().
If you truly want to mutate the vector's elements while filtering it, you can use the nightly-only method Vec::drain_filter, an extremely flexible tool:
#![feature(drain_filter)]
fn main() {
let mut vec = vec![1, 2, 3, 4];
vec.drain_filter(|x| {
if *x % 2 == 0 {
true
} else {
*x += 100;
false
}
});
assert_eq!(vec, [101, 103]);
}
It also allows you to get the removed elements as the return value of the entire method is an iterator!
Till Vec::drain_filter gets stable, we can solve the problem with homebrewed rust:
fn main() {
let mut v = vec![1, 2, 3, 4];
let mut i = 0;
while i < v.len() {
if v[i] % 2 == 0 {
v.remove(i);
} else {
v[i] += 100;
i += 1;
}
}
println!("{:?}", v); // [101, 103]
}
BTW remove() is an O(n) operation but doesn't allocate memory.
Playground
I am providing my take for this problem as I was unaware of the retain method:
impl<T> RemoveFilter<T> for Vec<T> {}
pub trait RemoveFilter<T>: BorrowMut<Vec<T>> {
fn remove_filter<F: for<'b> FnMut(&'b T) -> bool>(&mut self, mut cb: F) {
let vec: &mut Vec<T> = self.borrow_mut();
let mut write_to = 0;
let mut read_from = 0;
while read_from < vec.len() {
let maintain = cb(&mut vec[read_from]);
if maintain {
vec.as_mut_slice().swap(read_from, write_to);
write_to += 1;
}
read_from += 1;
}
vec.resize_with(write_to, || panic!("We are shrinking the vector"));
}
}
It will shift the elements as it iterates and then remove anything that is left behind. I think this is code may easily modified to solve other problems.