This question already has an answer here:
Do mutable references have move semantics?
(1 answer)
Closed 1 year ago.
Let me give the code first
fn dump(iter: &mut dyn Iterator<Item=String>) {
for (i, v) in iter.enumerate() {
println!("{} {}", i, v);
}
for v in iter {
println!("{}", v);
}
}
#[test]
fn test_trait() {
let v = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let mut iter = v.into_iter();
dump(&mut iter);
}
Here is the output when I run this test
running 1 test
0 a
1 b
2 c
test test_trait ... ok
Why the iter not moved when calling enumerate?
The enumerate is accepting self as its first argument, so I think it should move the iter,
but it doesn't! The second for-loop can still run, without any compilation error.
In this case, Self is actually &mut (dyn Iterator<Item = String>) making the enumerate call return Enumerate<&mut (dyn Iterator<Item = String>)>. I am not that familiar how Rust deals with this kind of dynamic trait objects but my guess is that what gets dropped at the end of enumeration is actually the reference.
By the way - if you are using VSCode and the Rust analyzer extension, you can turn on the "Inlay Hints: Type Hints" option to see the types of things.
There is a similar option for the Intellij Idea IDE that I can not remember off the top of my head. That way I was able to see the type by making a variable of the enumeration and this is what it showed:
let a: Enumerate<&mut (dyn Iterator<Item = String>)>
Related
This question already has answers here:
Why can't I use `&Iterator<Item = &String>` as an iterator?
(3 answers)
How do I create a function that accepts an iterator of i32s as either values or references and sums them?
(1 answer)
How to write a Rust function that takes an iterator?
(3 answers)
Closed 2 years ago.
I have a function that takes a &Vector<T>. I want to change it to take an iterator in order to run it on different container/collection/slice types.
It produces an error because the function is called twice.
What I Have So Far
fn operate_on_iterator<'a>(iterator: &impl IntoIterator<Item = i32>) -> i32 {
// This is an example. Please don't tell me to use `.sum`.
let mut sum = 0;
for val in iterator.into_iter() {
sum += val;
}
sum
}
fn caller() -> i32 {
let v = vec![1, 2, 3, 4];
let s1 = operate_on_iterator(&v);
let s2 = operate_on_iterator(&v);
s1 + s2
}
playground
The Error I Get
error[E0507]: cannot move out of `*iterator` which is behind a shared reference
--> src/lib.rs:13:16
|
13 | for val in iterator.into_iter() {
| ^^^^^^^^ move occurs because `*iterator` has type `impl IntoIterator<Item = i32>`, which does not implement the `Copy` trait
Restrictions and notes
I do not want to use dyn because I prefer the slightly larger code size over the performance impact of pointer dereferencing. (Although I will use it for now and will benchmark it once I have both traits and trait objects implemented, i.e. after I have an answer to this question.) Also using dyn also didn't work so far for me.
I have used this answer as a basis. How to write a Rust function that takes an iterator?
My Item implements Clone, Binding, and Drop.
I also tried to implement it using Iterator instead of IntoIterator. Also no luck.
Shepmaster linked to the answer.
For completeness, this is the necessary change:
&impl IntoIterator<Item = i32> -->
impl IntoIterator<Item = &'a i32>
Resulting in this code:
fn operate_on_iterator<'a>(iterator: impl IntoIterator<Item = &'a i32>) -> i32 {
// This is an example. Please don't tell me to use `.sum`.
let mut sum = 0;
for val in iterator.into_iter() {
sum += val;
}
sum
}
The struct std::vec::Vec implements two kinds of Extend, as specified here – impl<'a, T> Extend<&'a T> for Vec<T> and impl<T> Extend<T> for Vec<T>. The documentation states that the first kind is an "Extend implementation that copies elements out of references before pushing them onto the Vec". I'm rather new to Rust, and I'm not sure if I'm understanding it correctly.
I would guess that the first kind is used with the equivalent of C++ normal iterators, and the second kind is used with the equivalent of C++ move iterators.
I'm trying to write a function that accepts any data structure that will allow inserting i32s to the back, so I take a parameter that implements both kinds of Extend, but I can't figure out how to specify the generic parameters to get it to work:
fn main() {
let mut vec = std::vec::Vec::<i32>::new();
add_stuff(&mut vec);
}
fn add_stuff<'a, Rec: std::iter::Extend<i32> + std::iter::Extend<&'a i32>>(receiver: &mut Rec) {
let x = 1 + 4;
receiver.extend(&[x]);
}
The compiler complains that &[x] "creates a temporary which is freed while still in use" which makes sense because 'a comes from outside the function add_stuff. But of course what I want is for receiver.extend(&[x]) to copy the element out of the temporary array slice and add it to the end of the container, so the temporary array will no longer be used after receiver.extend returns. What is the proper way to express what I want?
From the outside of add_stuff, Rect must be able to be extended with a reference whose lifetime is given in the inside of add_stuff. Thus, you could require that Rec must be able to be extended with references of any lifetime using higher-ranked trait bounds:
fn main() {
let mut vec = std::vec::Vec::<i32>::new();
add_stuff(&mut vec);
}
fn add_stuff<Rec>(receiver: &mut Rec)
where
for<'a> Rec: std::iter::Extend<&'a i32>
{
let x = 1 + 4;
receiver.extend(&[x]);
}
Moreover, as you see, the trait bounds were overly tight. One of them should be enough if you use receiver consistently within add_stuff.
That said, I would simply require Extend<i32> and make sure that add_stuff does the right thing internally (if possible):
fn add_stuff<Rec>(receiver: &mut Rec)
where
Rec: std::iter::Extend<i32>
{
let x = 1 + 4;
receiver.extend(std::iter::once(x));
}
I'm trying to write some Rust code to decode GPS data from an SDR receiver. I'm reading samples in from a file and converting the binary data to a series of complex numbers, which is a time-consuming process. However, there are times when I want to stream samples in without keeping them in memory (e.g. one very large file processed only one way or samples directly from the receiver) and other times when I want to keep the whole data set in memory (e.g. one small file processed in multiple different ways) to avoid repeating the work of parsing the binary file.
Therefore, I want to write functions or structs with iterators to be as general as possible, but I know they aren't sized, so I need to put them in a Box. I would have expected something like this to work.
This is the simplest example I could come up with to demonstrate the same basic problem.
fn sum_squares_plus(iter: Box<Iterator<Item = usize>>, x: usize) -> usize {
let mut ans: usize = 0;
for i in iter {
ans += i * i;
}
ans + x
}
fn main() {
// Pretend this is an expensive operation that I don't want to repeat five times
let small_data: Vec<usize> = (0..10).collect();
for x in 0..5 {
// Want to iterate over immutable references to the elements of small_data
let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter());
println!("{}: {}", x, sum_squares_plus(iterbox, x));
}
// 0..100 is more than 0..10 and I'm only using it once,
// so I want to 'stream' it instead of storing it all in memory
let x = 55;
println!("{}: {}", x, sum_squares_plus(Box::new(0..100), x));
}
I've tried several different variants of this, but none seem to work. In this particular case, I'm getting
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, usize> as std::iter::Iterator>::Item == usize`
--> src/main.rs:15:52
|
15 | let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found usize
|
= note: expected type `&usize`
found type `usize`
= note: required for the cast to the object type `dyn std::iter::Iterator<Item = usize>`
I'm not worried about concurrency and I'd be happy to just get it working sequentially on a single thread, but a concurrent solution would be a nice bonus.
The current error you're running into is here:
let iterbox:Box<Iterator<Item = usize>> = Box::new(small_data.iter());
You're declaring that you want an iterator that returns usize items, but small_data.iter() is an iterator that returns references to usize items (&usize). That why you get the error "expected reference, found usize". usize is a small type that's cloneable so you can simply use the .cloned() iterator adapter to provide an iterator that actually returns a usize.
let iterbox: Box<Iterator<Item = usize>> = Box::new(small_data.iter().cloned());
Once you're past that hurdle, the next problem is that the iterator returned over small_data contains a reference to the small_data. Since sum_squares_plus is defined to accept a Box<Iterator<Item = usize>>, it's implied in that signature that the Iterator trait object within the box has a 'static lifetime. The iterator you're providing does not because it borrows small_data. To fix that you need to adjust the sum_squares_plus definition to
fn sum_squares_plus<'a>(iter: Box<Iterator<Item = usize> + 'a>, x: usize) -> usize
Note the 'a lifetime annotations. The code should then compile, but unless there's some constraints other than what's clearly defined here, a more idiomatic and efficient approach would be to avoid using trait objects and the associated allocations. The below code should work using static dispatch without any trait objects.
fn sum_squares_plus<I: Iterator<Item = usize>>(iter: I, x: usize) -> usize {
let mut ans: usize = 0;
for i in iter {
ans += i * i;
}
ans + x
}
fn main() {
// Pretend this is an expensive operation that I don't want to repeat five times
let small_data: Vec<usize> = (0..10).collect();
for x in 0..5 {
println!("{}: {}", x, sum_squares_plus(small_data.iter().cloned(), x));
}
// 0..100 is more than 0..10 and I'm only using it once,
// so I want to 'stream' it instead of storing it all in memory
let x = 55;
println!("{}: {}", x, sum_squares_plus(Box::new(0..100), x));
}
This question already has answers here:
Why does creating a mutable reference to a dereferenced mutable reference work?
(3 answers)
Why can't I reuse a &mut reference after passing it to a function that accepts a generic type?
(1 answer)
Closed 4 years ago.
I have this program:
use std::io::{self, Cursor, prelude::*};
fn file_op<R: Read>(mut reader: R) -> io::Result<()> {
// Some file operation
let mut buf = [0u8];
reader.read(&mut buf)?;
Ok(())
}
fn main() -> io::Result<()> {
let mut f = Cursor::new(vec![0xffu8]);
// Works
file_op(&mut f)?;
file_op(&mut f)?;
let x = &mut f;
// Does not work
file_op(x)?;
file_op(x)?;
Ok(())
}
I understand that the first portion (// Works) works because any &mut T where T: Read also implements Read (from impl<'a, R: Read + ?Sized> Read for &'a mut R in libstd).
However, I don't understand why the second portion (// Does not work) causes a use after move error. Isn't the R type parameter a &mut Cursor (which implements Read) in both cases? If I'm only using references, what is getting moved? The reference variable, x, itself?
error[E0382]: use of moved value: `x`
--> src/main.rs:21:13
|
20 | file_op(x)?;
| - value moved here
21 | file_op(x)?;
| ^ value used here after move
|
= note: move occurs because `x` has type `&mut std::io::Cursor<std::vec::Vec<u8>>`, which does not implement the `Copy` trait
Interestingly, dereferencing x and referencing it again also works:
file_op(&mut *x)?;
file_op(&mut *x)?;
Despite thoroughly reading the documentation, I'm rather confused about the meaning of the & and * symbol in Rust, and more generally about what is a Rust reference exactly.
In this example, it seems to be similar to a C++ reference (that is, an address that is automatically dereferenced when used):
fn main() {
let c: i32 = 5;
let rc = &c;
let next = rc + 1;
println!("{}", next); // 6
}
However, the following code works exactly the same:
fn main() {
let c: i32 = 5;
let rc = &c;
let next = *rc + 1;
println!("{}", next); // 6
}
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
My understanding so far, is that, inserting * in front of a Rust reference dereferences it, but the * is implicitly inserted anyway so you don't need to add it (while in C++, it's implicitly inserted and if you insert it you get a compilation error).
However, something like this doesn't compile:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = rc + 1;
}
println!("{}", next);
}
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`
--> src/main.rs:6:16
|
6 | next = rc + 1;
| ^^^^^^
|
= note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work
= note: an implementation of `std::ops::Add` might be missing for `&mut i32`
But this works:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = *rc + 1;
}
println!("{}", next); // 6
}
It seems that implicit dereferencing (a la C++) is correct for immutable references, but not for mutable references. Why is this?
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
A reference in C++ is not the same as a reference in Rust. Rust's references are much closer (in usage, not in semantics) to C++'s pointers. With respect to memory representation, Rust's references often are just a single pointer, while C++'s references are supposed to be alternative names of the same object (and thus have no memory representation).
The difference between C++ pointers and Rust references is that Rust's references are never NULL, never uninitialized and never dangling.
The Add trait is implemented (see the bottom of the doc page) for the following pairs and all other numeric primitives:
&i32 + i32
i32 + &i32
&i32 + &i32
This is just a convenience thing the std-lib developers implemented. The compiler can figure out that a &mut i32 can be used wherever a &i32 can be used, but that doesn't work (yet?) for generics, so the std-lib developers would need to also implement the Add traits for the following combinations (and those for all primitives):
&mut i32 + i32
i32 + &mut i32
&mut i32 + &mut i32
&mut i32 + &i32
&i32 + &mut i32
As you can see that can get quite out of hand. I'm sure that will go away in the future. Until then, note that it's rather rare to end up with a &mut i32 and trying to use it in a mathematical expression.
This answer is for those looking for the basics (e.g. coming from Google).
From the Rust book's References and Borrowing:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].
The opposite of referencing by using & is dereferencing, which is accomplished with the dereference operator, *.
And a basic example:
let x = 5;
let y = &x; //set y to a reference to x
assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
If we tried to write assert_eq!(5, y); instead, we would get a compilation error can't compare `{integer}` with `&{integer}`.
(You can read more in the Smart Pointers chapter.)
And from Method Syntax:
Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:
p1.distance(&p2);
(&p1).distance(&p2);
From the docs for std::ops::Add:
impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32
It seems the binary + operator for numbers is implemented for combinations of shared (but not mutable) references of the operands and owned versions of the operands. It has nothing to do with automatic dereferencing.