I'm attempting to simply convert a slice to a vector. The following code:
let a = &[0u8];
let b: Vec<u8> = a.iter().collect();
fails with the following error message:
3 | let b: Vec<u8> = a.iter().collect();
| ^^^^^^^ a collection of type `std::vec::Vec<u8>` cannot be built from an iterator over elements of type `&u8`
What am I missing?
Collecting into a Vec is so common that slices have a method to_vec that does exactly this:
let b = a.to_vec();
You get the same thing as CodesInChaos's answer, but more concisely.
Notice that to_vec requires T: Clone. To get a Vec<T> out of a &[T] you have to be able to get an owned T out of a non-owning &T, which is what Clone does.
Slices also implement ToOwned, so you can use to_owned instead of to_vec if you want to be generic over different types of non-owning container. If your code only works with slices, prefer to_vec instead.
The iterator only returns references to the elements (here &u8). To get owned values (here u8), you can used .cloned().
let a: &[u8] = &[0u8];
let b: Vec<u8> = a.iter().cloned().collect();
Related
I'm modifying a library that holds Items returned by ChunkExact slice iterator. My iterator requires interior mutability and uses a RefCell. As a result of that, my iterator cannot return Items of type &[u8] but returns Ref<'_, [u8]> instead. The two types seem to be equivalent for practical use. For instance, this:
for i in slice.chunks_exact(2) {
println!("{:?}", i);
}
works just as well as this:
for my_iterator() {
println!("{:?}", i);
}
Full working example in the playground.
Close as they are, I cannot convert one item into the other:
= note: expected enum `Option<Ref<'_, [u8]>>`
found enum `Option<&[u8]>`
I saw the experimental cell::Ref::leak method, but seems like what I'm trying to do should not require such a scary feature...
You can use Option::as_deref:
let a: Option<Ref<'_, [u8]>> = ...;
let b: Option<&[u8]> = a.as_deref();
Ref<'_, T> implements Deref<Target = T> which is why Ref<'_, [u8]> can be used like a &[u8] in most contexts. However, they are still different types, which is why you get the error on assigning one to the other in an option.
You cannot go the other way around and create a Ref<'_, T> from a &T since there is no RefCell for it to reference.
This will only work in a context where the original Option<Ref> is kept around. You cannot use this to convert your iterator from returning Ref<'_, [u8]>s to returning &[u8]s. This is because the lifetime of the &[u8] is bound to the Ref, not the original RefCell.
I have a program where I need to append two Vec<u8> before they are are serialized.
Just to be sure how to do it, I made this example program:
let a: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let b: Vec<u8> = vec![7, 8, 9];
let c = [a, b].concat();
println!("{:?}", c);
Which works perfectly. The issue is now when I have to implement it in my own project.
Here I need to write a function, the function takes a struct as input that looks like this:
pub struct Message2 {
pub ephemeral_key_r: Vec<u8>,
pub c_r: Vec<u8>,
pub ciphertext2: Vec<u8>,
}
and the serialalization function looks like this:
pub fn serialize_message_2(msg: &Message2) -> Result<Vec<u8>> {
let c_r_and_ciphertext = [msg.c_r, msg.ciphertext2].concat();
let encoded = (
Bytes::new(&msg.ephemeral_key_r),
Bytes::new(&c_r_and_ciphertext),
);
Ok(cbor::encode_sequence(encoded)?)
}
The first issue that arises here is that it complains that msg.ciphertext2 and msg.c_r are moved values. This makes sense, so I add an & in front of both of them.
However, when I do this, the call to concat() fails, with this type error:
util.rs(77, 59): method cannot be called on `[&std::vec::Vec<u8>; 2]` due to unsatisfied trait bounds
So, when I borrow the values, then the expression [&msg.c_r, &msg.ciphertext2] becomes an array of two vec's, which there is not a concat() defined for.
I also tried calling clone on both vectors:
let c_r_and_ciphertext = [msg.c_r.clone(), msg.ciphertext2.clone()].concat();
and this actually works out!
But now I'm just wondering, why does borrowing the values change the types?
and is there any things to think about when slapping on clone to values that are moved, and where I cannot borrow for some reason?
The reasons on why .concat() behaves as it does are a bit awkward.
To be able to call .concat(), the Concat trait must be implemented. It is implemented on slices of strings, and slices of V, where V can be Borrowed as slices of copyable T.
First, you're calling concat on an array, not a slice. However, auto-borrowing and unsize coercion are applied when calling a function with .. This turns the [V; 2] into a &[V] (where V = Vec<u8> in the working case and V = &Vec<u8> in the non-workin case). Try calling Concat::concat([a, b]) and you'll notice the difference.
So now is the question whether V can be borrowed as/into some &[T] (where T = u8 in your case). Two possibilities exist:
There is an impl<T> Borrow<[T]> for Vec<T>, so Vec<u8> can be turned into &[u8].
There is an impl<'_, T> Borrow<T> for &'_ T, so if you already have a &[u8], that can be used.
However, there is no impl<T> Borrow<[T]> for &'_ Vec<T>, so concatting [&Vec<_>] won't work.
So much for the theory, on the practical side: You can avoid the clones by using [&msg.c_r[..], &msg.ciphertext2[..]].concat(), because you'll be calling concat on &[&[u8]]. The &x[..] is a neat trick to turn the Vecs into slices (by slicing it, without slicing anything off…). You can also do that with .borrow(), but that's a bit more awkward, since you may need an extra type specification: [msg.c_r.borrow(), msg.ciphertext2.borrow()].concat::<u8>()
I tried to reproduce your error message, which this code does:
fn main() {
let a = vec![1, 2];
let b = vec![3, 4];
println!("{:?}", [&a, &b].concat())
}
gives:
error[E0599]: the method `concat` exists for array `[&Vec<{integer}>; 2]`, but its trait bounds were not satisfied
--> src/main.rs:4:31
|
4 | println!("{:?}", [&a, &b].concat())
| ^^^^^^ method cannot be called on `[&Vec<{integer}>; 2]` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`[&Vec<{integer}>]: Concat<_>`
It is a simple matter of helping the compiler to see that &a works perfectly fine as a slice, by calling it &a[..]:
fn main() {
let a = vec![1, 2];
let b = vec![3, 4];
println!("{:?}", [&a[..], &b[..]].concat())
}
why does borrowing the values change the types?
Borrowing changes a type into a reference to that same type, so T to &T. These types are related, but are not the same.
is there any things to think about when slapping on clone to values that are moved, and where I cannot borrow for some reason?
Cloning is a good way to sacrifice performance to make the borrow checker happy. It (usually) involves copying the entire memory that is cloned, but if your code is not performance critical (which most code is not), then it may still be a good trade-off...
I have a function that takes in a Vec<String> value. I want to use this function on values contained inside my_ref, so I need to extract a Vec<String> out of a Rc<RefCell<Vec<String>>>.
I thought I could do this by dereferencing a borrow of my my_ref, just like I would for a Rc<RefCell<f32>>> or Rc<RefCell<i32>>> value:
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let my_ref = Rc::from(RefCell::from(vec![
"Hello 1".to_string(),
"Hello 2".to_string(),
]));
let my_strings: Vec<String> = *my_ref.borrow();
let count = count_strings(my_strings);
}
fn count_strings(strings: Vec<String>) -> usize {
strings.len()
}
But doing so results in a dereferencing error:
error[E0507]: cannot move out of dereference of `Ref<'_, Vec<String>>`
cannot move out of dereference of `Ref<'_, Vec<String>>`
move occurs because value has type `Vec<String>`, which does not implement the `Copy` trait
So then, how do I properly extract a Vec<String> from a Rc<RefCell<Vec<String>>>?
RefCell::borrow returns a reference, not an owned value, that's why you having such an error. I can name two different solution for that problem.
Promoting Rc to exclusively-owned type
Rc::try_unwrap is able to check, whether there's other references to the data. If it's the only one, it can be safely converted to the inner type. Then, an owned RefCell can be converted into its inner via into_inner function.
let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = Rc::try_unwrap(my_ref).expect("I hereby claim that my_ref is exclusively owned").into_inner();
Replacing inner value
If for some reason you want to grab inner value that is already referenced, you may consider replacing it. Note, that you need to create a appropriate value for the type (i.e. with trait Default). Here's the example:
let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = my_ref.borrow_mut().take();
// or
let inner: Vec<_> = my_ref.borrow_mut().replace(vec![]);
I'm confused about the proper type to use for an iterator yielding string slices.
fn print_strings<'a>(seq: impl IntoIterator<Item = &'a str>) {
for s in seq {
println!("- {}", s);
}
}
fn main() {
let arr: [&str; 3] = ["a", "b", "c"];
let vec: Vec<&str> = vec!["a", "b", "c"];
let it: std::str::Split<'_, char> = "a b c".split(' ');
print_strings(&arr);
print_strings(&vec);
print_strings(it);
}
Using <Item = &'a str>, the arr and vec calls don't compile. If, instead, I use <Item = &'a'a str>, they work, but the it call doesn't compile.
Of course, I can make the Item type generic too, and do
fn print_strings<'a, I: std::fmt::Display>(seq: impl IntoIterator<Item = I>)
but it's getting silly. Surely there must be a single canonical "iterator of string values" type?
The error you are seeing is expected because seq is &Vec<&str> and &Vec<T> implements IntoIterator with Item=&T, so with your code, you end up with Item=&&str where you are expecting it to be Item=&str in all cases.
The correct way to do this is to expand Item type so that is can handle both &str and &&str. You can do this by using more generics, e.g.
fn print_strings(seq: impl IntoIterator<Item = impl AsRef<str>>) {
for s in seq {
let s = s.as_ref();
println!("- {}", s);
}
}
This requires the Item to be something that you can retrieve a &str from, and then in your loop .as_ref() will return the &str you are looking for.
This also has the added bonus that your code will also work with Vec<String> and any other type that implements AsRef<str>.
TL;DR The signature you use is fine, it's the callers that are providing iterators with wrong Item - but can be easily fixed.
As explained in the other answer, print_string() doesn't accept &arr and &vec because IntoIterator for &[T; n] and &Vec<T> yield references to T. This is because &Vec, itself a reference, is not allowed to consume the Vec in order to move T values out of it. What it can do is hand out references to T items sitting inside the Vec, i.e. items of type &T. In the case of your callers that don't compile, the containers contain &str, so their iterators hand out &&str.
Other than making print_string() more generic, another way to fix the issue is to call it correctly to begin with. For example, these all compile:
print_strings(arr.iter().map(|sref| *sref));
print_strings(vec.iter().copied());
print_strings(it);
Playground
iter() is the method provided by slices (and therefore available on arrays and Vec) that iterates over references to elements, just like IntoIterator of &Vec. We call it explicitly to be able to call map() to convert &&str to &str the obvious way - by using the * operator to dereference the &&str. The copied() iterator adapter is another way of expressing the same, possibly a bit less cryptic than map(|x| *x). (There is also cloned(), equivalent to map(|x| x.clone()).)
It's also possible to call print_strings() if you have a container with String values:
let v = vec!["foo".to_owned(), "bar".to_owned()];
print_strings(v.iter().map(|s| s.as_str()));
I want to write a function in Rust that will return the vector composed of start integer, then all intermediate integers and then end integer. The assertion it should hold is this:
assert_eq!(intervals(0, 4, 1..4), vec![0, 1, 2, 3, 4]);
The hint is to use chain method for iterators. The function declaration is predefined, I implemented it in one way, which is the following code:
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
let mut a1 = vec![];
a1.push(start);
let inter: Vec<u32> = intermediate.into_iter().collect();
let mut iter : Vec<u32> = a1.iter().chain(inter.iter()).map(|x| *x).collect();
iter.push(end);
return iter;
}
But I am quite convinced this is not really optimal way to do this. I am sure I am doing lots of unnecessary things in the middle two lines. I tried to use intermediate directly like this:
let mut iter: Vec<u32> = a1.iter().chain(intermediate).map(|x| *x).collect();
But I am getting this error for chain method and I don't know how to solve it:
type mismatch resolving <I as std::iter::IntoIterator>::Item==&u32,
expected u32, found &u32
I am super new in Rust so any advice would be helpful to understand what's the right way to use intermediate parameter here.
Here are a few hints:
You have created three separate vectors (one explicitly, two using collect) when in fact you only need one.
You can use the std::iter::once iterator to produce iterators for the start and end integers
No need to collect the intermediate range. The intermediate argument implements IntoIterator, so you can feed it directly to chain. So, you can chain together the start, intermediate and end.
No need to use the 'return' keyword at the end of a function - the result of a function is the value of the last expression in it (as long as there is no semicolon on the end).
Applying those tips your function would look like this:
use std::iter::once;
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
once(start).chain(intermediate).chain(once(end)).collect()
}
One additional thing to note, to answer your question from the comments:
why trying this: a1.iter().chain(intermediate) gives an error with chain method
Calling Vec::iter() returns an iterator that returns references to the values in the vector. This makes sense: calling iter() does not consume the vector, and its contents remain intact: you could iterate over it multiple times if you wanted.
On the other hand, invoking into_iter() from the IntoIterator trait returns an iterator that returns the values. This also makes sense: into_iter() does consume the object you are calling it on, so the iterator then takes ownership of the items that were previously owned by the object.
Trying to chain together two such iterators does not work because they are each iterating different types. One resolution would be to consume a1 as well, like this:
let mut iter : Vec<u32> = a1.into_iter().chain(intermediate).collect();