Rust how to add two referenced i32's together? - rust

fn main() {
fn calculate_two_numbers<T:Debug, const N: usize>(data_set: [T;N]) -> (i32,i32) {
// Key Code
let a = &data_set[0]+&data_set[1];
println!("{:?},{:?},{:?}",&data_set[0],&data_set[1],a);
// Ignore
return (0,0)
}
let data = [1509,1857,1736,1815,1576];
let result = calculate_two_numbers(data);
}
I have a very simple function which takes a list of size n.
From this list, I want to take the first two variables and add them together. I then want to print all of them out with println!.
However, I get the error error[E0369]: cannot add &T to &T
This is the solution the complier suggests but I have trouble understanding it
fn calculate_two_numbers<T:Debug + std::ops::Add<Output = &T>, const N: usize>(data_set: [T;N])
Can someone explain what std::ops::Add<Output = &T> does?

In Rust, when using generic types, you need to tell the compiler what kind of operations you would want to do with the type. This is done be constraining the bounds of your type (You are already using it with Debug, it means you can use it as it were a debug type).
The compiler suggest to add the Add trait, but it will not really work straight away because of the references. You can either add a lifetime or use Copy (with would be probably desirable if you are gonna work with numbers), again add it as another bound:
use std::fmt::Debug;
use std::ops::Add;
fn calculate_two_numbers<T: Debug + Add::<Output=T> + Copy, const N: usize>(data_set: [T; N]) -> (i32, i32) {
// Key Code
let a = data_set[0] + data_set[1];
println!("{:?},{:?},{:?}", data_set[0], data_set[1], a);
// Ignore
return (0, 0);
}
fn main() {
let data = [1509, 1857, 1736, 1815, 1576];
let result = calculate_two_numbers(data);
}
Playground
If using the references approach, you need to specify that for any lifetime for your references that reference implements Add<Output=T>:
fn calculate_two_numbers<T: Debug, const N: usize>(data_set: [T; N]) -> (i32, i32)
where
for<'a> &'a T: Add<Output = T>,
{
// Key Code
let a = &data_set[0] + &data_set[1];
println!("{:?},{:?},{:?}", data_set[0], data_set[1], a);
// Ignore
return (0, 0);
}
Playground

Related

How to accept str.chars() or str.bytes() in a function and iterate twice?

Is there any way to pass somestring.chars() or somestring.bytes() to a function and allow that function to reconstruct the iterator?
An example is below. The goal is for the function to be able to iterate through coll multiple times, reconstructing it as needed using into_iter(). It works correctly for vectors and arrays, but I have not been able to get it working for the string iterator methods.
// Lifetime needed to indicate the iterator objects
// don't disappear
fn test_single<'a, I, T>(collection: &'a I)
where
&'a I: IntoIterator<Item = T>,
T: Display,
{
let count = collection.into_iter().count();
println!("Len: {}", count);
for x in collection.into_iter() {
println!("Item: {}", x);
}
}
fn main() {
// Works
test_single(&[1, 2, 3, 4]);
test_single(&vec!['a', 'b', 'c', 'd']);
let s = "abcd";
// Desired usage; does not work
// test_single(&s.chars());
// test_single(&s.bytes());
}
The general error is that Iterator is not implemented for &Chars<'_>. This doesn't make sense because chars definitely does implement IntoIterator and Iterator
Is there a solution that allows for the desired usage of test_single(&s.chars())?
Link to the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=230ee86cd109384a1c62c362aed9d47f
(IntoIterator is prefered over Iterator for my application, since I also need to specify that IntoIterator::IntoIter is a DoubleEndedIterator.)
This can work but not the way you have it written.
You can't iterate a shared reference because Iterator::next() takes &mut self. IntoIterator::into_iter() could be made to work with e.g. &Chars, but that's not necessary because Chars and Bytes both implement Clone, which creates a copy of the iterator (but doesn't duplicate the underlying data).
So you just need to adjust your bounds and accept the iterator by value, cloning it when you will need another iterator later:
fn test_single<I, T>(collection: I)
where
I: Clone + IntoIterator<Item = T>,
T: Display,
{
let count = collection.clone().into_iter().count();
println!("Len: {}", count);
for x in collection.into_iter() {
println!("Item {}", x);
}
}
Now you can call test_single(s.chars()), for example.
(Playground)
Side note: You can express the type I purely with impl, which might be more readable:
fn test_single(collection: impl Clone + IntoIterator<Item=impl Display>) {

Returning iterator from weak references for mapping and modifying values

I'm trying quite complex stuff with Rust where I need the following attributes, and am fighting the compiler.
Object which itself lives from start to finish of application, however, where internal maps/vectors could be modified during application lifetime
Multiple references to object that can read internal maps/vectors of an object
All single threaded
Multiple nested iterators which are map/modified in lazy manner to perform fast and complex calculations (see example below)
A small example, which already causes problems:
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Weak;
pub struct Holder {
array_ref: Weak<RefCell<Vec<isize>>>,
}
impl Holder {
pub fn new(array_ref: Weak<RefCell<Vec<isize>>>) -> Self {
Self { array_ref }
}
fn get_iterator(&self) -> impl Iterator<Item = f64> + '_ {
self.array_ref
.upgrade()
.unwrap()
.borrow()
.iter()
.map(|value| *value as f64 * 2.0)
}
}
get_iterator is just one of the implementations of a trait, but even this example already does not work.
The reason for Weak/Rc is to make sure that multiple places points to object (from point (1)) and other place can modify its internals (Vec<isize>).
What is the best way to approach this situation, given that end goal is performance critical?
EDIT:
Person suggested using https://doc.rust-lang.org/std/cell/struct.Ref.html#method.map
But unfortunately still can't get - if I should also change return type - or maybe the closure function is wrong here
fn get_iterator(&self) -> impl Iterator<Item=f64> + '_ {
let x = self.array_ref.upgrade().unwrap().borrow();
let map1 = Ref::map(x, |x| &x.iter());
let map2 = Ref::map(map1, |iter| &iter.map(|y| *y as f64 * 2.0));
map2
}
IDEA say it has wrong return type
the trait `Iterator` is not implemented for `Ref<'_, Map<std::slice::Iter<'_, isize>, [closure#src/bin/main.rs:30:46: 30:65]>>`
This won't work because self.array_ref.upgrade() creates a local temporary Arc value, but the Ref only borrows from it. Obviously, you can't return a value that borrows from a local.
To make this work you need a second structure to own the Arc, which can implement Iterator in this case since the produced items aren't references:
pub struct HolderIterator(Arc<RefCell<Vec<isize>>>, usize);
impl Iterator for HolderIterator {
type Item = f64;
fn next(&mut self) -> Option<f64> {
let r = self.0.borrow().get(self.1)
.map(|&y| y as f64 * 2.0);
if r.is_some() {
self.1 += 1;
}
r
}
}
// ...
impl Holder {
// ...
fn get_iterator<'a>(&'a self) -> Option<impl Iterator<Item=f64>> {
self.array_ref.upgrade().map(|rc| HolderIterator(rc, 0))
}
}
Alternatively, if you want the iterator to also weakly-reference the value contained within, you can have it hold a Weak instead and upgrade on each next() call. There are performance implications, but this also makes it easier to have get_iterator() be able to return an iterator directly instead of an Option, and the iterator written so that a failed upgrade means the sequence has ended:
pub struct HolderIterator(Weak<RefCell<Vec<isize>>>, usize);
impl Iterator for HolderIterator {
type Item = f64;
fn next(&mut self) -> Option<f64> {
let r = self.0.upgrade()?
.borrow()
.get(self.1)
.map(|&y| y as f64 * 2.0);
if r.is_some() {
self.1 += 1;
}
r
}
}
// ...
impl Holder {
// ...
fn get_iterator<'a>(&'a self) -> impl Iterator<Item=f64> {
HolderIterator(Weak::clone(&self.array_ref), 0)
}
}
This will make it so that you always get an iterator, but it's empty if the Weak is dead. The Weak can also die during iteration, at which point the sequence will abruptly end.

How deal with Option<Ref<T>> and Option<&T>

In the example we assume that we have two codes that has their perimeter and tested individually.
The code 1 return the type Option<Rc<RefCell<T>>>
and code 2 that have to consume &T.
I have an issues with the following example playground.
use std::cell::RefCell;
use std::rc::Rc;
// Code 2
fn action(data_1: Option<&i32>, data_2: Option<&i32>) {
println!("data_1:{:?}, data_2:{:?}", data_1, data_2);
}
fn main() {
// Code 1
let data_1 = Some(Rc::new(RefCell::new(2)));
let data_2 = Some(Rc::new(RefCell::new(5)));
let ref_data_1 = data_1.as_ref().map(|r| r.borrow());
let ref_data_2 = data_2.as_ref().map(|r| r.borrow());
action(ref_data_1, ref_data_2); // Error: mismatched types
}
The example fail because of mismatch types between Ref<T> is found and &T is expected.
My only way that I have founded is to change Option<&i32> to Option<Ref<i32>> but that break the interface of code 2.
You can change the action function to accept either Option<&i32> or Option<Ref<i32>> by using a generic argument with a Deref<Target = i32> bound, which both of those types satisfy:
use std::ops::Deref;
fn action<T>(data_1: Option<T>, data_2: Option<T>)
where
T: Deref<Target = i32>,
{
println!("data_1:{:?}, data_2:{:?}", data_1.as_deref(), data_2.as_deref());
}
If you can't or don't want to change the signature of action, then you can call as_deref() on the arguments when you pass them in:
action(ref_data_1.as_deref(), ref_data_2.as_deref());

Why does this variable definition imply static lifetime?

I'm trying to execute a function on chunks of a vector and then send the result back using the message passing library.
However, I get a strange error about the lifetime of the vector that isn't even participating in the thread operations:
src/lib.rs:153:27: 154:25 error: borrowed value does not live long enough
src/lib.rs:153 let extended_segments = (segment_size..max_val)
error: src/lib.rs:154 .collect::<Vec<_>>()borrowed value does not live long enough
note: reference must be valid for the static lifetime...:153
let extended_segments = (segment_size..max_val)
src/lib.rs:153:3: 155:27: 154 .collect::<Vec<_>>()
note: but borrowed value is only valid for the statement at 153:2:
reference must be valid for the static lifetime...
src/lib.rs:
let extended_segments = (segment_size..max_val)
consider using a `let` binding to increase its lifetime
I tried moving around the iterator and adding lifetimes to different places, but I couldn't get the checker to pass and still stay on type.
The offending code is below, based on the concurrency chapter in the Rust book. (Complete code is at github.)
use std::sync::mpsc;
use std::thread;
fn sieve_segment(a: &[usize], b: &[usize]) -> Vec<usize> {
vec![]
}
fn eratosthenes_sieve(val: usize) -> Vec<usize> {
vec![]
}
pub fn segmented_sieve_parallel(max_val: usize, mut segment_size: usize) -> Vec<usize> {
if max_val <= ((2 as i64).pow(16) as usize) {
// early return if the highest value is small enough (empirical)
return eratosthenes_sieve(max_val);
}
if segment_size > ((max_val as f64).sqrt() as usize) {
segment_size = (max_val as f64).sqrt() as usize;
println!("Segment size is larger than √{}. Reducing to {} to keep resource use down.",
max_val,
segment_size);
}
let small_primes = eratosthenes_sieve((max_val as f64).sqrt() as usize);
let mut big_primes = small_primes.clone();
let (tx, rx): (mpsc::Sender<Vec<usize>>, mpsc::Receiver<Vec<usize>>) = mpsc::channel();
let extended_segments = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
for this_segment in extended_segments.clone() {
let small_primes = small_primes.clone();
let tx = tx.clone();
thread::spawn(move || {
let sieved_segment = sieve_segment(&small_primes, this_segment);
tx.send(sieved_segment).unwrap();
});
}
for _ in 1..extended_segments.count() {
big_primes.extend(&rx.recv().unwrap());
}
big_primes
}
fn main() {}
How do I understand and avoid this error? I'm not sure how to make the lifetime of the thread closure static as in this question and still have the function be reusable (i.e., not main()). I'm not sure how to "consume all things that come into [the closure]" as mentioned in this question. And I'm not sure where to insert .map(|s| s.into()) to ensure that all references become moves, nor am I sure I want to.
When trying to reproduce a problem, I'd encourage you to create a MCVE by removing all irrelevant code. In this case, something like this seems to produce the same error:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>()
.chunks(segment_size);
}
fn main() {}
Let's break that down:
Create an iterator between numbers.
Collect all of them into a Vec<usize>.
Return an iterator that contains references to the vector.
Since the vector isn't bound to any variable, it's dropped at the end of the statement. This would leave the iterator pointing to an invalid region of memory, so that's disallowed.
Check out the definition of slice::chunks:
fn chunks(&self, size: usize) -> Chunks<T>
pub struct Chunks<'a, T> where T: 'a {
// some fields omitted
}
The lifetime marker 'a lets you know that the iterator contains a reference to something. Lifetime elision has removed the 'a from the function, which looks like this, expanded:
fn chunks<'a>(&'a self, size: usize) -> Chunks<'a, T>
Check out this line of the error message:
help: consider using a let binding to increase its lifetime
You can follow that as such:
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo = (segment_size..max_val)
.collect::<Vec<_>>();
let bar = foo.chunks(segment_size);
}
fn main() {}
Although I'd write it as
fn segmented_sieve_parallel(max_val: usize, segment_size: usize) {
let foo: Vec<_> = (segment_size..max_val).collect();
let bar = foo.chunks(segment_size);
}
fn main() {}
Re-inserting this code back into your original problem won't solve the problem, but it will be much easier to understand. That's because you are attempting to pass a reference to thread::spawn, which may outlive the current thread. Thus, everything passed to thread::spawn must have the 'static lifetime. There are tons of questions that detail why that must be prevented and a litany of solutions, including scoped threads and cloning the vector.
Cloning the vector is the easiest, but potentially inefficient:
for this_segment in extended_segments.clone() {
let this_segment = this_segment.to_vec();
// ...
}

Is it possible to have stack allocated arrays with the size determined at runtime in Rust?

Is there an equivalent of alloca to create variable length arrays in Rust?
I'm looking for the equivalent of the following C99 code:
void go(int n) {
int array[n];
// ...
}
It is not possible directly, as in there is not direct syntax in the language supporting it.
That being said, this particular feature of C99 is debatable, it has certain advantages (cache locality & bypassing malloc) but it also has disadvantages (easy to blow-up the stack, stumps a number of optimizations, may turn static offsets into dynamic offsets, ...).
For now, I would advise you to use Vec instead. If you have performance issues, then you may look into the so-called "Small Vector Optimization". I have regularly seen the following pattern in C code where performance is required:
SomeType array[64] = {};
SomeType* pointer, *dynamic_pointer;
if (n <= 64) {
pointer = array;
} else {
pointer = dynamic_pointer = malloc(sizeof(SomeType) * n);
}
// ...
if (dynamic_pointer) { free(dynamic_pointer); }
Now, this is something that Rust supports easily (and better, in a way):
enum InlineVector<T, const N: usize> {
Inline(usize, [T; N]),
Dynamic(Vec<T>),
}
You can see an example simplistic implementation below.
What matters, however, is that you now have a type which:
uses the stack when less than N elements are required
moves off to the heap otherwise, to avoid blowing up the stack
Of course, it also always reserves enough space for N elements on the stack even if you only use 2; however in exchange there is no call to alloca so you avoid the issue of having dynamic offsets to your variants.
And contrary to C, you still benefit from lifetime tracking so that you cannot accidentally return a reference to your stack-allocated array outside the function.
Note: prior to Rust 1.51, you wouldn't be able to customize by N.
I will show off the most "obvious" methods:
enum SmallVector<T, const N: usize> {
Inline(usize, [T; N]),
Dynamic(Vec<T>),
}
impl<T: Copy + Clone, const N: usize> SmallVector<T, N> {
fn new(v: T, n: usize) -> Self {
if n <= N {
Self::Inline(n, [v; N])
} else {
Self::Dynamic(vec![v; n])
}
}
}
impl<T, const N: usize> SmallVector<T, N> {
fn as_slice(&self) -> &[T] {
match self {
Self::Inline(n, array) => &array[0..*n],
Self::Dynamic(vec) => vec,
}
}
fn as_mut_slice(&mut self) -> &mut [T] {
match self {
Self::Inline(n, array) => &mut array[0..*n],
Self::Dynamic(vec) => vec,
}
}
}
use std::ops::{Deref, DerefMut};
impl<T, const N: usize> Deref for SmallVector<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T, const N: usize> DerefMut for SmallVector<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
Usage:
fn main() {
let mut v = SmallVector::new(1u32, 4);
v[2] = 3;
println!("{}: {}", v.len(), v[2])
}
Which prints 4: 3 as expected.
No.
Doing that in Rust would entail the ability to store Dynamically Sized Types (DSTs) like [i32] on the stack, which the language doesn't support.
A deeper reason is that LLVM, to my knowledge, doesn't really support this. I'm given to believe that you can do it, but it significantly interferes with optimisations. As such, I'm not aware of any near-terms plans to allow this.

Resources