I have a Reader that I want to prepend some bytes to, creating a Chain. Ideally I'd want to do this:
use std::io::{Chain, Read};
fn thingify<R: Read>(r: R) -> Chain<[u8; 3], R> {
let mut arr = [1u8, 2u8, 3u8];
// Modify arr here
return arr.chain(r);
}
But that throws a compiler error:
error[E0308]: mismatched types
--> test.rs:7:12
|
3 | fn thingify<R: Read>(r: R) -> Chain<[u8; 3], R>
| ----------------- expected `std::io::Chain<[u8; 3], R>` because of return type
...
7 | return arr.chain(r);
| ^^^^^^^^^^^^ expected array of 3 elements, found &[u8]
|
= note: expected type `std::io::Chain<[u8; 3], _>`
found type `std::io::Chain<&[u8], _>`
From what I understand, this seems to be because Read is implemented for slices rather than arrays, and somehow my array decays to a slice here.
But when I change the array in the return type to a slice and give it an explicit lifetime like so:
use std::io::{Chain, Read};
fn thingify<'a, R: Read>(r: R) -> Chain<&'a [u8], R> {
let arr = [1u8, 2u8, 3u8];
// Modify arr here
return arr.chain(r);
}
I just get another compiler error instead:
error[E0515]: cannot return value referencing local variable `arr`
--> test.rs:19:12
|
19 | return arr.chain(r);
| ---^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `arr` is borrowed here
How can I transfer ownership of my array to the Chain so that I can return it? Is that simply not doable with a [u8]?
Because Read is implemented for &'_ [u8] but not for [u8; 3], the compiler automatically converts your array into a reference slice. This mean your array must be valid as long as the slice live so as long as the Chain live.
There are several solutions, you could ask to the caller a mutable slice, you could make it static if you want to be able to mutate it, if you don't you can make it const, if you need to resize it you need a Vec, etc...
use std::io::{stdin, Chain, Read};
fn a<R: Read>(arr: &mut [u8; 3], r: R) -> Chain<&[u8], R> {
arr.copy_from_slice(&[1, 2, 3]);
arr.chain(r)
}
fn b<R: Read>(r: R) -> Chain<&'static [u8], R> {
const ARR: [u8; 3] = [1, 2, 3];
ARR.chain(r)
}
fn main() {
let mut arr = [0; 3];
println!("{:?}", a(&mut arr, stdin()));
println!("{:?}", b(stdin()));
}
See:
Is there any way to return a reference to a variable created in a function?
Related
I need the trait XYZ to define a method that allows iterating over some set of integers. This set of integers is defined either by a backing Vec or by a Range<usize>. However, I run into various (lifetime or type) issues depending on how I define the XYZIterator type that is supposed to unify these Iterators over Vec/Range.
The backup solution would be to allocate and return Vecs, but I wondered whether there was a way without cloning/allocating memory.
type XYZIterator = Box<dyn Iterator<Item = usize>>;
trait XYZ {
fn stuff(&self) -> XYZIterator;
}
struct Test {
objects: Vec<usize>,
}
impl XYZ for Test {
fn stuff(&self) -> XYZIterator {
Box::new(self.objects.iter())
}
}
struct Test2 {}
impl XYZ for Test2 {
fn stuff(&self) -> XYZIterator {
Box::new((1..4).into_iter())
}
}
fn main() {
let t1 = Test {
objects: vec![1, 2, 3],
};
let t2 = Test2 {};
t1.stuff().for_each(|x| println!("{}", x));
t2.stuff().for_each(|x| println!("{}", x));
t1.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
t2.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
}
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, usize> as Iterator>::Item == usize`
--> src/main.rs:12:9
|
12 | Box::new(self.objects.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
|
= note: expected type `usize`
found reference `&usize`
= note: required for the cast to the object type `dyn Iterator<Item = usize>`
Your code has two issues:
In the implementation of XYZ for Test1, you return the iterator self.objects.iter(). Vec::iter iterates over references to the objects, not objects themselves, so this is an iterator over &usize, which doesn't match the return type. You should have gotten an error about this. It's easy to fix though: self.objects.iter().copied() will copy each element out of the reference.
In type XYZIterator = Box<dyn Iterator<Item = usize>>;, since there is no lifetime in the trait object, it defaults to 'static - that is, your iterator can live forever. But that's not the case with the vector iterator - it has a reference to the vector is iterating over. This is where you are having lifetime issues.
The solution is to give the XYZIterator type a lifetime:
type XYZIterator<'a> = Box<dyn Iterator<Item = usize> + 'a>;
And alter the traits and trait implementations to use the lifetime.
Also consider altering your type or function to accept any T: Iterator<Item=usize>; it will then accept any iterator that produces usizes
How to use std::cmp::Reverse with binary_search_by_key? Example: Rust-Playground
The documentation to Rust's Vec::binary_search_by_key says:
Assumes that the slice is sorted by the key, for instance with sort_by_key using the same key extraction function.
In the minimal example below, I am using the same extraction function -- but no luck.
use std::cmp::Reverse;
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
v.sort_by_key(|&num| Reverse(num));
println!("{:?}", v);
let index = v.binary_search_by_key(&1, |&num| Reverse(num));
println!("Res: {:?}", index);
}
This complains about mismatched types: "expected integer, found struct std::cmp::Reverse".
error[E0308]: mismatched types
--> src/main.rs:8:51
|
8 | let index = v.binary_search_by_key(&1, |&num| Reverse(num));
| ^^^^^^^^^^^^ expected integer, found struct `std::cmp::Reverse`
|
= note: expected type `{integer}`
found struct `std::cmp::Reverse<{integer}>`
Careful inspection of the function signature gives the answer.
pub fn binary_search_by_key<'a, B, F>(
&'a self,
b: &B,
f: F
) -> Result<usize, usize> where
B: Ord,
F: FnMut(&'a T) -> B,
B is the return value of the function, and also the first argument (after &self).
Therefore we have to add Reverse to the first argument as well:
v.binary_search_by_key(&Reverse(1), |&num| Reverse(num))
I encountered an error when trying to use a function get_even_numbers() to borrow a vec v by passing it in by reference &v instead of by value v.
fn get_even_numbers(v: &Vec<i32>) -> Vec<i32> {
v.iter().filter(|x| x % 2 == 0).collect()
}
fn main() {
let v: Vec<i32> = (0..10).collect();
let even: Vec<i32> = get_even_numbers(&v);
println!("Even numbers: {:?}", even);
}
error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `&i32`
--> src/main.rs:2:37
|
2 | v.iter().filter(|x| x % 2 == 0).collect()
| ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=&i32>`
|
= help: the trait `FromIterator<&i32>` is not implemented for `Vec<i32>`
= help: the trait `FromIterator<T>` is implemented for `Vec<T>`
note: required by a bound in `collect`
Why does the above give an error, but passing it in by value does not, as shown below?
fn get_even_numbers(v: Vec<i32>) -> Vec<i32> {
v.into_iter().filter(|x| x % 2 == 0).collect()
}
fn main() {
let v: Vec<i32> = (0..10).collect();
let even: Vec<i32> = get_even_numbers(v);
println!("Even numbers: {:?}", even);
}
Even numbers: [0, 2, 4, 6, 8]
I used .iter() inside the function when passing in by reference and .into_iter() when passing in by value, not sure if these are the correct functions to use.
Use v.iter().filter(|x| x % 2 == 0).cloned().collect(). That will (trivially) clone each of the &i32 references into actual i32 values.
I'm confused by how Rust for loops work. Consider the following:
#![feature(core_intrinsics)]
fn print_type_of<T>(_: T) {
println!("{}", unsafe { std::intrinsics::type_name::<T>() });
}
fn main() {
let nums = vec![1, 2, 3];
for num in &nums { print_type_of(num); }
for num in nums { print_type_of(num); }
}
It outputs the following:
&i32
&i32
&i32
i32
i32
i32
What does it mean to pass in a vector into for versus a reference to a vector? Why, when you pass in a reference, do you get a reference to the items and when you pass in an actual vector, you get the actual items?
The argument to a for loop must implement IntoIterator. If you check out the docs for Vec, you will see these two implementations of IntoIterator:
impl<T> IntoIterator for Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>
}
impl<'a, T> IntoIterator for &'a Vec<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>
}
You get references for &vec and values for vec because that's how the iterators are defined.
Sometimes, you'll see these as the more explicit forms: iter or into_iter. The same logic applies; see What is the difference between iter and into_iter?
There's another form that you will encounter: &mut vec and iter_mut. These return mutable references to the elements in the vector.
As to why the differences at all...
Using a reference to the vector allows you to access the vector after the loop is done. This compiles:
let v = vec![1, 2, 3];
for i in &v {}
for i in &v {}
This does not:
let v = vec![1, 2, 3];
for i in v {}
for i in v {}
error[E0382]: use of moved value: `v`
--> src/main.rs:4:14
|
3 | for i in v {}
| - value moved here
4 | for i in v {}
| ^ value used here after move
|
= note: move occurs because `v` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
Ownership-wise, you can't get a value from a reference unless you clone the value (assuming the type can even be cloned!). This means &vec is unable to yield values that aren't references.
The implementer of Vec's iterator could have chosen to only yield references, but transferring ownership of the elements to the iterator allows the iterator's consumer to do more things; from a capability perspective it's preferred.
See also:
What is the difference between iter and into_iter?
Why can I iterate over a slice twice, but not a vector?
I have a function which selects a different array based on whether a boolean is set to true or false, similar to the following:
const V1: [u8; 2] = [1,2];
const V2: [u8; 4] = [1,2,3,4];
fn test(b: bool) {
let v = if b { &V1 } else { &V2 };
}
fn main() {
test(false);
}
However I get the following error:
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:5:33
|
5 | let v = if b { &V1 } else { &V2 };
| --- ^^^ expected an array with a fixed size of 2 elements, found one with 4 elements
| |
| expected because of this
|
= note: expected type `&[u8; 2]`
found reference `&[u8; 4]`
I tried storing the constants as vectors, but to_vec cannot be used for constants.
An alternative would be to copy the array into a vector inside test, but I'd rather not have to make copies every time.
Is there a way to do this without copying the array every whenever the function is called?
The answer is to use slices, but unfortunately the rust type inference isn't clever enough to realize that. If you annotate the type of v explicitly as an &[u8] then everything should compile.
const V1: [u8; 2] = [1,2];
const V2: [u8; 4] = [1,2,3,4];
fn test(b: bool) {
let v: &[u8] = if b { &V1 } else { &V2 };
}
fn main() {
test(false);
}
Rust must know the type and lifetime of all variables at compile time; in this case, you are using the [u8] type, which is a slice type for u8 elements. Slices are stored as a reference to the first element as well as the number of elements. For example, your V1 slice stores u8 elements and there are 2 of them and V2 stores u8 elements and there are 4 of them. But note that these two are not the same type because of the difference in the number of elements.
So, if you'd like to return a borrowed value of one of the two slices (V1 or V2) you are able to do so as long as the compiler has two pieces of information; the type and their lifetime. We know that the compiler can figure out the type of both V1 and V2 since it is explicitly declared and they both live in static memory (data is part of the program source), so all we have to do is say that we are returning a reference to a slice (borrow) of u8s and they will be around for as long as the program is running (static lifetime). And even though V1 and V2 are not the same type, they look the same when you borrow them since all we are saying is that the return value references a bunch of u8 elements and we leave it up to the compiler to make sure it knows the number of elements for each at compile time. Check out the working example below.
const V1: [u8; 2] = [1,2];
const V2: [u8; 4] = [1,2,3,4];
fn test(b: bool) -> &'static [u8] {
let v: &[u8] = if b { &V1 } else { &V2 };
v
}
fn main() {
println!("{:?}", test(false));
}
As a final note, when attempting to solve these problems, don't be afraid to make mistakes; the compiler is actually quite friendly and very helpful when trying to figure out what to do next as shown in the error message below.
|
6 | fn test(b: bool) -> &[u8] {
| ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments