This question already has answers here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
How can I sum up using concurrency from 1 to 1000000 with Rust?
(1 answer)
Closed 3 years ago.
I have an array of strings. I would like to count the total chars but using threads for parallelisation (the original problem is not this but is similar).
use std::thread;
pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
let handlers: Vec<thread::JoinHandle<usize>> = input
.chunks(worker_count)
.map(|chunk| thread::spawn(calculate(chunk)))
.collect();
let hashes = handlers.into_iter().map(|handler| handler.join().unwrap());
let mut sum = 0;
for h in hashes {
sum += h
}
sum
}
fn calculate<'a>(input: &'a [&'a str]) -> impl Fn() -> usize + 'a {
move || input.iter().map(|s| s.len()).sum()
}
The compiler tells me this:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:5:10
|
5 | .chunks(worker_count)
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 3:18...
--> src/lib.rs:3:18
|
3 | pub fn frequency<'a>(input: &'a [&'a str], worker_count: usize) -> usize {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:4:52
|
4 | let handlers: Vec<thread::JoinHandle<usize>> = input
| ^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `impl std::ops::Fn<()>` will meet its required lifetime bounds
--> src/lib.rs:6:22
|
6 | .map(|chunk| thread::spawn(calculate(chunk)))
| ^^^^^^^^^^^^^
I've tried to remove all lifetimes, use different lifetimes for str and the slice, and explicitly invoke calculate::<'a> but none of those solutions compile.
The input lifetime is the same everywhere: frequency declares 'a that is used in calculate, so the closure is bound to 'a because the captured variables live for 'a.
Where am I wrong?
NB: I would like not to use 'static.
Related
I'm currently implementing a ray tracer following along the book "The Ray Tracer Challenge" by Jamis Buck.
I've arrived at the part where I have to implement a few methods on matrices, and since these matrices have a compile time known size, I chose to implement them using const generics expressions (which are still only available on the nightly channel).
#![feature(generic_const_exprs)]
The Matrix type is defined as the following:
#[derive(Debug)]
pub struct Matrix<const N: usize>(pub [[f64; N]; N]);
I implemented the following methods:
impl<const N: usize> Matrix<N> {
fn submatrix(&self, index: Idx) -> Matrix<{ N - 1 }> {
//...
}
fn minor(&self, index: Idx) -> f64
where
[(); N - 1]:,
{
let submatrix = self.submatrix(index);
submatrix.determinant()
}
fn cofactor(&self, index: Idx) -> f64
where
[(); N - 1]:,
{
let minor = self.minor(index);
//...
}
fn determinant(&self) -> f64
where
[(); N - 1]:,
{
//...
}
}
... but I'm running into an issue with the submatrix method, which returns a Matrix<{ N - 1 }>.
When calling the determinant method on a submatrix, which is what we do in the minor method:
fn minor(&self, index: Idx) -> f64
where
[(); N - 1]:,
{
let submatrix: Matrix<{ N - 1 }> = self.submatrix(index);
submatrix.determinant()
}
... even though the minor method is bounded by the following constraint:
where [(); N - 1]:,
... the compiler still complains and suggests to add the same where bound using this expression:
error: unconstrained generic constant
--> src/rt/matrix.rs:109:19
|
109 | submatrix.determinant()
| ^^^^^^^^^^^
|
= help: try adding a `where` bound using this expression: `where [(); N - 1]:`
note: required by a bound in `Matrix::<N>::determinant`
--> src/rt/matrix.rs:128:14
|
126 | fn determinant(&self) -> f64
| ----------- required by a bound in this
127 | where
128 | [(); N - 1]:,
| ^^^^^ required by this bound in `Matrix::<N>::determinant`
I tried to implement the minor method for Matrix<{ N - 1 }> but it does not seem to work either (or rather I have no idea how to do that, or if that's even possible):
impl<const N: usize> Matrix<{ N - 1 }> {
fn minor(&self, index: Idx) -> f64 {
let submatrix = self.submatrix(index);
submatrix.determinant()
}
... which gives the following error:
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> src/rt/matrix.rs:138:12
|
138 | impl<const N: usize> Matrix<{ N - 1 }> {
| ^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported
I'm wondering if what I'm trying to do here with the submatrix is even possible. It's not a big deal since I can define these methods for each possible N, which in my case are limited to 2_usize, 3_usize and 4_usize, but implementing these methods only for Matrix<N> would be a lot cleaner!
Warning: The generic_const_exprs feature is extremely unstable! Do not use it in production!
You call determinant() on submatrix, which is already Matrix<{ N - 1 }> (returned from submatrix()). So you can to also restrict it to where [(); N - 1 - 1]:, (note that the Rust compiler is not smart enough to understand this is the same as where [(); N - 2]:,, nor it is able to conclude that if this holds then also where [(); N - 1]:,. You have to write both: where [(); N - 1]:, [(); N - 1 - 1]:,):
fn minor(&self, index: Idx) -> f64
where
[(); N - 1]:,
[(); N - 1 - 1]:,
{
let submatrix = self.submatrix(index);
submatrix.determinant()
}
fn cofactor(&self, index: Idx) -> f64
where
[(); N - 1]:,
[(); N - 1 - 1]:,
{
let minor = self.minor(index);
//...
}
This question already has answers here:
Can I destructure a tuple without binding the result to a new variable in a let/match/for statement?
(3 answers)
How to swap two variables?
(2 answers)
Closed 3 years ago.
I’m getting an error I’m not sure how to handle, related to a tuple assignment I’m trying. The incr function below gets a left-hand of expression not valid error. What am I misunderstanding?
struct Fib {
i: u64,
fa: u64,
fb: u64,
}
impl Fib {
fn incr(&mut self) {
self.i += 1;
(self.fa, self.fb) = (self.fa + self.fb, self.fa);
}
}
As the helpful error explanation says†, you try to assign to a non-place expression. A place expression represents a memory location, and thus it can be a variable, a dereference, an indexing expression or a field reference, but a tuple is not one of these.
If you would use a binding, such as:
let (x, y) = (1, 2);
that would be a whole different story because let statements have different rules than assignment: the left hand side of a let statement is a pattern, not an expression, and (x, y) is a legal pattern.
To solve your problem, you may want to do the following and introduce a temporary variable, and then update the values of the members:
(The following is also fixing your fibonacci sequence, i.e. correcting the values of the members since they are naturally ordered as 'a' and 'b')
impl Fib {
fn incr(&mut self) {
self.i += 1;
let fa = self.fa;
self.fa = self.fb;
self.fb += fa;
}
}
Note: Albeit it was not your question, I would strongly advise to implement Iterator for your Fib type, in which case you wouldn't have to keep track of the index (i) because that would be available through the enumerate method.
E.g.
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
let fa = self.fa;
self.fa = self.fb;
self.fb += fa;
Some(fa)
}
}
And then you could use it as:
for (i, x) in my_fib.enumerate() { ... }
† rustc --explain E0070
I am trying to do the following (which doesn't compile):
let Parse<'T> value =
Enum.Parse(typedefof<'T>, value) :?> 'T
In short I would like to pass an enum type, and a string and get back an enum value.
An example usage would be:
type MyEnums =
| Green = 0,
| Blue = 1
and then:
let r = Parse<MyEnums> "Green"
what would be the syntax? I haven't used generics yet in F#, so this is what I came up with from reading the docs.
bonus question would be if there is a way to parse enums in a case insensitive way (besides turning everything to lowercase for example)
This does compile for me (also without true, did you open System?):
let Parse<'T> value =
System.Enum.Parse(typedefof<'T>, value, true) :?> 'T
and works case-insensitive for
type MyEnums =
| Green = 0
| Blue = 1
Parse<MyEnums> "Green" // Green
Parse<MyEnums> "blue" // Blue
I came up with this in a hurry, which I believe has the advantage of not accepting other types than enums. Haven't had time to google for a better way, if there is one. Also, the underlying type must be int, and I haven't had time to see if there's something to be done with that either.
type MyEnum = | A = 1 | B = 2
let parseEnum<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType and 'T : enum<int>> v =
match Enum.TryParse<'T> v with
| true, v -> Some v
| false, _ -> None
let x = parseEnum<MyEnum> "B"
match x with
| Some x -> printfn "%A" x
| None -> printfn "Sorry"
// let z = parseEnum<int> "1" // won't compile
I want to write a function that uses breadth-first search on a binary tree to print node values in order:
use std::collections::VecDeque;
use std::ops::Deref;
struct BinarySearchNode<'a> {
value: &'a str,
key: i32,
left: Option<Box<BinarySearchNode<'a>>>,
right: Option<Box<BinarySearchNode<'a>>>,
}
impl<'a> BinarySearchNode<'a> {
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
queue.push_back(&self);
while let Some(ref current) = queue.pop_front() {
if let Some(left_node) = current.left {
queue.push_back(&left_node.deref());
}
if let Some(right_node) = current.right {
queue.push_back(&right_node.deref());
}
output = output + current.value + "\n";
}
output
}
}
fn main() {}
I get the error
error: borrowed value does not live long enough
--> src/main.rs:19:34
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the statement at 19:16
--> src/main.rs:19:17
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> src/main.rs:19:17
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `left_node` does not live long enough
--> src/main.rs:19:34
|
19 | queue.push_back(&left_node.deref());
| ^^^^^^^^^
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the if let at 18:12
--> src/main.rs:18:13
|
18 | if let Some(left_node) = current.left {
| ^
error: borrowed value does not live long enough
--> src/main.rs:22:34
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the statement at 22:16
--> src/main.rs:22:17
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> src/main.rs:22:17
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `right_node` does not live long enough
--> src/main.rs:22:34
|
22 | queue.push_back(&right_node.deref());
| ^^^^^^^^^^
|
note: reference must be valid for the block suffix following statement 0 at 13:40...
--> src/main.rs:13:41
|
13 | let mut queue = VecDeque::new();
| ^
note: ...but borrowed value is only valid for the if let at 21:12
--> src/main.rs:21:13
|
21 | if let Some(right_node) = current.right {
| ^
error[E0507]: cannot move out of borrowed content
--> src/main.rs:18:38
|
18 | if let Some(left_node) = current.left {
| --------- ^^^^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref left_node` or `ref mut left_node`
error[E0507]: cannot move out of borrowed content
--> src/main.rs:21:39
|
21 | if let Some(right_node) = current.right {
| ---------- ^^^^^^^ cannot move out of borrowed content
| |
| hint: to prevent move, use `ref right_node` or `ref mut right_node`
I needed to deref() because simply using the operator * was causing a type mismatch as it expected a reference and not a box. It seems those dereference slightly differently and at least in stable I can't destructure it either.
I get that this value is scoped within the while loop and doesn't live long enough to be in the VecDeque (if this is the right data structure for the job) but I'm not sure what the best way to go about extending that lifetime is or if there's simply a better way to write this entire thing as it feels a bit complex.
My main problem is that I'm not sure where to start refactoring this code and I surprisingly had a hard time finding examples of a breadth-first search performed on a binary tree in Rust to take patterns from.
Your main problem lies in this line (and the right version):
if let Some(left_node) = current.left
This tries to move the value contained in current.left into the pattern on the right side. the problem is that current.left is an Option<Box<BinarySearchNode<'a>>>. When you move the Box out of current, that would leave current without a valid value for left! Accessing that value in the future would lead to bad behavior.
Instead, you need to leave the value where it is and instead take a reference. The two main ways are to use the ref pattern modifier:
if let Some(ref left_node) = current.left
Or to call as_ref:
if let Some(left_node) = current.left.as_ref()
Here is complete code:
use std::collections::VecDeque;
struct BinarySearchNode<'a> {
value: &'a str,
key: i32,
left: Option<Box<BinarySearchNode<'a>>>,
right: Option<Box<BinarySearchNode<'a>>>,
}
impl<'a> BinarySearchNode<'a> {
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
queue.push_back(self);
while let Some(current) = queue.pop_front() {
if let Some(left_node) = current.left.as_ref() {
queue.push_back(left_node);
}
if let Some(right_node) = current.right.as_ref() {
queue.push_back(right_node);
}
output = output + current.value + "\n";
}
output
}
}
fn main() {
let root = BinarySearchNode {
value: "a",
key: 0,
left: Some(Box::new(BinarySearchNode {
value: "b",
key: 1,
left: None,
right: None,
})),
right: Some(Box::new(BinarySearchNode {
value: "c",
key: 2,
left: None,
right: None,
})),
};
println!("{}", root.print());
}
Try this one:
pub fn print(&self) -> String {
let mut queue = VecDeque::new();
let mut output = String::new();
if let Some(ref left_node) = self.left {
queue.push_back(left_node);
}
if let Some(ref right_node) = self.right {
queue.push_back(right_node);
}
while let Some(ref current) = queue.pop_front() {
if let Some(ref left_node) = current.left {
queue.push_back(left_node);
}
if let Some(ref right_node) = current.right {
queue.push_back(right_node);
}
output = output + current.value + "\n";
}
output
}
I'm new to Rust and looking to understand concepts like borrowing. I'm trying to create a simple two dimensional array using standard input. The code:
use std::io;
fn main() {
let mut values = [["0"; 6]; 6]; // 6 * 6 array
// iterate 6 times for user input
for i in 0..6 {
let mut outputs = String::new();
io::stdin().read_line(&mut outputs).expect(
"failed to read line",
);
// read space separated list 6 numbers. Eg: 5 7 8 4 3 9
let values_itr = outputs.trim().split(' ');
let mut j = 0;
for (_, value) in values_itr.enumerate() {
values[i][j] = value;
j += 1;
}
}
}
This won't compile because the outputs variable lifetime is not long enough:
error[E0597]: `outputs` does not live long enough
--> src/main.rs:20:5
|
14 | let values_itr = outputs.trim().split(' ');
| ------- borrow occurs here
...
20 | }
| ^ `outputs` dropped here while still borrowed
21 | }
| - borrowed value needs to live until here
How can I get the iterated values out of the block into values array?
split() gives you substrings (string slices) borrowed from the original string, and the original string is outputs from line 6.
The string slices can't outlive the scope of outputs: when a loop iteration ends, outputs is deallocated.
Since values is longer lived, the slices can't be stored there.
We can't borrow slices of outputs across a modification of outputs. So even if the String outputs itself was defined before values, we couldn't easily put the string slices from .split() into values; modifying the string (reading into it) invalidates the slices.
A solution needs to either
Use a nested array of String, and when you assign an element from the split iterator, make a String from the &str using .to_string(). I would recommend this solution. (However an array of String is not at as easy to work with, maybe already this requires using Vec instead.) 1
Read all input before constructing a nested array of &str that borrows from the input String. This is good if the nested array is something that you only need temporarily.
1: You can use something like vec![vec![String::new(); 6]; 6] instead
This answer was moved from the question, where it solved the OPs needs.
use std::io;
fn main() {
let mut values = vec![vec![String::new(); 6]; 6];
for i in 0..6 {
let mut outputs = String::new();
io::stdin().read_line(&mut outputs)
.expect("failed to read line");
let values_itr = outputs.trim().split(' ');
let mut j = 0;
for (_, value) in values_itr.enumerate() {
values[i][j] = value.to_string();
j += 1;
}
}
}