Random sampling of a string slice - rust

The objective is to take a set number of random samples from a string slice.
fn get_random_samples<'a>(kmers: &'a [&'a str], sample_size: usize) -> &'a [&'a str] {
let mut rng = rand::thread_rng();
kmers
.choose_multiple(&mut rng, sample_size)
.map(|item| *item)
.collect::<Vec<&str>>()
.as_slice()
}
But the above code gives the following compilation error which I have no idea how to fix.
error[E0515]: cannot return reference to temporary value
--> src\lib.rs:382:5
|
382 | kmers
| _____^
| |_____|
| ||
383 | || .choose_multiple(&mut rng, sample_size)
384 | || .map(|item| *item)
385 | || .collect::<Vec<&str>>()
| ||_______________________________- temporary value created here
386 | | .as_slice()
| |____________________^ returns a reference to data owned by the current function

Just return the Vec directly (and remove the unnecessarily restrictive lifetime on the outer slice of kmers). Also, you can use Iterator::copied instead of map with deref.
fn get_random_samples<'a>(kmers: &[&'a str], sample_size: usize) -> Vec<&'a str> {
let mut rng = rand::thread_rng();
kmers
.choose_multiple(&mut rng, sample_size)
.copied()
.collect::<Vec<&str>>()
}
Playground demo

Related

Cannot move out of `*X` which is behind a shared reference when using Box

I understand the reason why this error is being raised, but not sure how I should go about fixing it. Ideally I would want to avoid using Copy.
fn get_random_samples<'a>(kmers: &[Box<str>], sample_size: usize) -> Vec<Box<str>> {
let mut rng = rand::thread_rng();
kmers
.choose_multiple(&mut rng, sample_size)
.map(|item| *item)
.collect::<Vec<Box<str>>>()
}
This raises the compilation error:
error[E0507]: cannot move out of `*item` which is behind a shared reference
--> src\lib.rs:384:21
|
384 | .map(|item| *item)
| ^^^^^ move occurs because `*item` has type `Box<str>`, which does not implement the `Copy` trait
I've also tried:
fn get_random_samples<'a>(kmers: &[Box<str>], sample_size: usize) -> Vec<Box<str>> {
let mut rng = rand::thread_rng();
kmers
.choose_multiple(&mut rng, sample_size)
.copied()
.collect::<Vec<Box<str>>>()
}
as learned from a previous question (Random sampling of a string slice), but this raises a different error:
error[E0277]: the trait bound `Box<str>: std::marker::Copy` is not satisfied
--> src\lib.rs:384:10
|
384 | .copied()
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `Box<str>`
|
note: required by a bound in `std::iter::Iterator::copied`
--> C:\Users\shant\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\iter\traits\iterator.rs:2987:12
|
2987 | T: Copy,
| ^^^^ required by this bound in `std::iter::Iterator::copied`
Both errors seem to point to the Copy trait which ideally I would like to avoid.
Any help would be appreciated!.
PS: Quite new to Rust, please do suggest if there's better ways to do this.
If you want to avoid copying/cloning, you need to return a reference. For example:
use rand::prelude::SliceRandom;
fn get_random_samples(kmers: &[Box<str>], sample_size: usize) -> Vec<&Box<str>> {
let mut rng = rand::thread_rng();
kmers
.choose_multiple(&mut rng, sample_size)
.collect()
}
Playground
or:
use rand::prelude::SliceRandom;
fn get_random_samples(kmers: &[Box<str>], sample_size: usize) -> Vec<&str> {
let mut rng = rand::thread_rng();
kmers.choose_multiple(&mut rng, sample_size).map(|e| e as &str).collect()
}
Playground

Cannot use the entry API to mutate a HashMap using a reference as the key inside of a function

I'm trying to get a handle to an element in a mutable HashMap reference where the keys are &str.
In the example below, I'm trying to get value dict[key] so I can mutate it. How do I do this?
I've tried:
dict.entry(key): lifetime mismatch
dict.entry(&String::from(key)): borrowed value does not live long enough
e.g. this:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
let num = dict.entry(&String::from(key)).or_insert(0);
*num += 1;
return 42;
}
Errors out with:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:4:27
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| - let's call the lifetime of this reference `'1`
4 | let num = dict.entry(&String::from(key)).or_insert(0);
| ------------^^^^^^^^^^^^^^^^^- - temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'1`
Link the lifetime of the key argument to the lifetime of the keys in the HashMap:
use std::collections::HashMap;
fn do_thing<'a>(key: &'a str, dict: &mut HashMap<&'a str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
dict.entry(key)
The error message for this version helps understand the problem:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
error[E0623]: lifetime mismatch
--> src/lib.rs:4:17
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| ---- ----
| |
| these two types are declared with different lifetimes...
4 | *dict.entry(key).or_insert(0) += 1;
| ^^^ ...but data from `key` flows into `dict` here
Specifically, entry will store key in the HashMap, but the value referenced by key might become invalid before the HashMap does. If that happened, the HashMap would contain a dangling reference, pointing to invalid memory. That's exactly what Rust's borrow checker prevents.
See also:
When is it required to use lifetimes?
Why are explicit lifetimes needed in Rust?
dict.entry(&String::from(key))
This can never work here, for much the same reason.
See also:
Return local String as a slice (&str)

How to return a Filter iterator filtering by struct members

I am trying to write a Tic-Tac-Toe game on the console. For one method of my Board struct, I'd like to return all positions of a certain type.
type PlayerID = i32;
type Position = (usize, usize);
#[derive(PartialEq)]
pub enum TileState {
Player(PlayerID),
None,
}
pub struct Board {
board: [[TileState; 3]; 3],
}
impl Board {
const ALL_POSITIONS: [Position; 3] = [(0, 0), (0, 1), (0, 2)];
pub fn free_tiles<'a>(&'a self) -> impl Iterator<Item = Position> + 'a {
Board::ALL_POSITIONS
.iter()
.filter(|(x, y)| self.board[*x][*y] == TileState::None)
.cloned()
}
}
Compiler error:
error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function
--> src/lib.rs:20:21
|
20 | .filter(|(x, y)| self.board[*x][*y] == TileState::None)
| ^^^^^^^^ ---- `self` is borrowed here
| |
| may outlive borrowed value `self`
|
note: closure is returned here
--> src/lib.rs:18:9
|
18 | / Board::ALL_POSITIONS
19 | | .iter()
20 | | .filter(|(x, y)| self.board[*x][*y] == TileState::None)
21 | | .cloned()
| |_____________________^
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
|
20 | .filter(move |(x, y)| self.board[*x][*y] == TileState::None)
| ^^^^^^^^^^^^^
Preferably, I'd like to avoid having to copy ALL_POSITIONS, self.board or create a new array in any other way.
What would be the best Rust style to solve this problem?

Satisfying lifetimes for function arguments [duplicate]

This question already has answers here:
How do I write the lifetimes for references in a type constraint when one of them is a local reference?
(1 answer)
How does "for<>" syntax differ from a regular lifetime bound?
(1 answer)
Closed 3 years ago.
This code takes some of the ideas of replace_with and extends it to structures, allowing a function to be applied to a container in a way that cleans up after itself if there's a panic. Unlike running replace_with on all the elements, one doesn't need a default value for the element types, only the container type.
I can't get the lifetimes right. If I replace TStruct with Vec<T> everything works fine without lifetime annotations, it's only when I try to generalise the function that I get lifetime issues. What lifetimes do I need to put in here to satisfy the borrow checker?
fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
f: impl Fn(T) -> T,
mut x: TStruct,
) -> TStruct
where
&mut TStruct: IntoIterator<Item = &mut T>,
&TStruct: IntoIterator<Item = &T>,
{
let x_ptr: *mut TStruct = &mut x;
for item_ref in &mut x {
let ptr: *mut T = item_ref;
unsafe {
let y1: T = std::ptr::read(ptr);
let fix_missing_elem = RunOnDrop {
f: || {
let y: TStruct = std::ptr::read(x_ptr);
let mut i = 0;
for item_ref in &y {
let current_item_ptr: *const T = item_ref;
if current_item_ptr == ptr {
break;
}
i += 1;
}
let mut j = 0;
for elem_ref in y {
if j == i {
std::mem::forget(elem_ref);
}
j += 1;
}
std::ptr::write(x_ptr, <TStruct as Default>::default());
},
};
let result = f(y1);
std::mem::forget(fix_missing_elem);
std::ptr::write(ptr, result);
}
}
x
}
struct RunOnDrop<F: FnMut()> {
f: F,
}
impl<'a, F: FnMut()> Drop for RunOnDrop<F> {
fn drop(&mut self) {
(self.f)()
}
}
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:6:5
|
6 | &mut TStruct: IntoIterator<Item = &mut T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:6:39
|
6 | &mut TStruct: IntoIterator<Item = &mut T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:7:5
|
7 | &TStruct: IntoIterator<Item = &T>,
| ^ explicit lifetime name needed here
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/lib.rs:7:35
|
7 | &TStruct: IntoIterator<Item = &T>,
| ^ explicit lifetime name needed here
error[E0310]: the parameter type `T` may not live long enough
--> src/lib.rs:1:1
|
1 | fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
| ^ - help: consider adding an explicit lifetime bound `T: 'static`...
| _|
| |
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
|
note: ...so that the reference type `&'static mut T` does not outlive the data it points at
--> src/lib.rs:1:1
|
1 | / fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
error[E0310]: the parameter type `TStruct` may not live long enough
--> src/lib.rs:1:1
|
1 | fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
| ^ -------- help: consider adding an explicit lifetime bound `TStruct: 'static`...
| _|
| |
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^
|
note: ...so that the reference type `&'static mut TStruct` does not outlive the data it points at
--> src/lib.rs:1:1
|
1 | / fn inplace_map<T, TStruct: IntoIterator<Item = T> + Default>(
2 | | f: impl Fn(T) -> T,
3 | | mut x: TStruct,
4 | | ) -> TStruct
... |
41 | | x
42 | | }
| |_^

Is "this represents potential undefined behavior in your code" error when using a match arm guard a bug in the compiler?

I'm having an issue with a match expression in my code raising a warning when a guard is included. I believe that this warning has to do with the non-lexical lifetimes used by the borrow checker. My function either returns a mutable reference to an item from a collection, or a clone of the whole collection.
#[derive(Debug, Clone)]
enum Value {
Int(i32),
List(Vec<Value>),
}
#[derive(Debug)]
struct Error(&'static str, Value);
fn main() {
let mut value = Value::List(vec![
Value::Int(1),
Value::Int(2),
Value::Int(34),
Value::Int(12),
]);
let y = index_list(&mut value, 2);
let _ = dbg!(y);
}
fn index_list<'a>(value: &'a mut Value, idx: usize) -> Result<&'a mut Value, Error> {
match *value {
Value::List(ref mut list) if idx < list.len() => Ok(&mut list[idx]),
Value::List(_) => Err(Error("index out of range", value.clone())),
_ => Err(Error("tried to index int", value.clone())),
}
}
playground
It compiles and runs, but I get a very ominous looking warning:
warning[E0502]: cannot borrow `*value` as immutable because it is also borrowed as mutable
--> src/main.rs:25:59
|
22 | fn index_list<'a>(value: &'a mut Value, idx: usize) -> Result<&'a mut Value, Error> {
| -- lifetime `'a` defined here
23 | match *value {
24 | Value::List(ref mut list) if idx < list.len() => Ok(&mut list[idx]),
| ------------ ------------------ returning this value requires that `value.0` is borrowed for `'a`
| |
| mutable borrow occurs here
25 | Value::List(_) => Err(Error("index out of range", value.clone())),
| ^^^^^ immutable borrow occurs here
|
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
warning[E0502]: cannot borrow `*value` as immutable because it is also borrowed as mutable
--> src/main.rs:26:46
|
22 | fn index_list<'a>(value: &'a mut Value, idx: usize) -> Result<&'a mut Value, Error> {
| -- lifetime `'a` defined here
23 | match *value {
24 | Value::List(ref mut list) if idx < list.len() => Ok(&mut list[idx]),
| ------------ ------------------ returning this value requires that `value.0` is borrowed for `'a`
| |
| mutable borrow occurs here
25 | Value::List(_) => Err(Error("index out of range", value.clone())),
26 | _ => Err(Error("tried to index int", value.clone())),
| ^^^^^ immutable borrow occurs here
|
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
I don't understand why the Err(value.clone()) line requires that the Ok(&mut ...) borrow still be active, because they are mutually exclusive and both result in a function return. This warning goes away if I remove the guard on the first match arm, but I need that guard to be there. Is this a bug in the NLL system? I never had this issue with the old borrowck. How can I make this better?
This error looks like a limitation of the borrow checker to me, similar to Double mutable borrow error in a loop happens even with NLL on. I can't see how this could lead to a soundness hole, and believe the code is safe.
When using an if statementat instead of match, the warning can be avoided, and the code becomes more readable as well:
fn bar<'a>(
map: &'a mut HashMap<String, Vec<i32>>,
name: &str,
idx: usize,
) -> Result<&'a mut i32, Vec<i32>> {
let value = map.get_mut(name).unwrap();
if idx < value.len() {
Ok(&mut value[idx])
} else {
Err(value.clone())
}
}

Resources