I'm trying to work my way up to rust and I'm stuck on a thing with generic types.
Surely you know the example from chapter 10.1 (Generic Data Types). I would like to create a vector that contains both the i32 vector and the char vector.
But somehow I can't get it to work.
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
}
I would now like to create a vector
let mut vecvec = Vec<Vec<T>>::new();
vecvec.push(number_list);
vecvec.push(char_list);
unfortunately, it doesn't work. I hope you have advice.
Thanks in advance.
First, "it doesn't work" is never helpful. It obviously "doesn't work" or you wouldn't be asking for help.
Second, providing the code you're actually working with (on the playground) is much easier than having to guess where the code "which doesn't work" is supposed to go.
Third,
let mut vecvec = Vec<Vec<T>>::new();
T needs to be defined somewhere, and it needs to be something that makes sense.
vecvec.push(number_list);
vecvec.push(char_list);
Vec<T> means all elements of a vec must have the same type. Here you have a Vec<i32> and a Vec<char>. They're not the same type and they can not be reconciled to the same type, so they can't be put in the same vector: Rust does not have ubiquitous type erasure or a "root type" à la Java, you can't just say that you have "a vector of vectors" and leave it at that with the blanks being filled at runtime.
This means you need some sort of indirection to "hide" the divergence, either an enum with a variant for each type of vec you want:
enum Wrapper {
Numbers(Vec<i32>),
Chars(Vec<char>)
}
Or a trait through which you can then use a trait object.
everybody,
here is the code that has now been created with the help of the answers. In case someone comes up with such an obscure idea ;)
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
enum Wrapper {
Numbers(Vec<i32>),
Chars(Vec<char>)
}
fn main() {
let mut number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let mut char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
let mut vec: Vec<Wrapper> = Vec::new();
vec.push(Wrapper::Numbers(number_list));
vec.push(Wrapper::Chars(char_list));
for v in vec.iter() {
match v {
Wrapper::Numbers(o) =>{ println!("The largest is {}", largest(o))},
Wrapper::Chars(c) => println!("The largest is {}", largest(c))
}
}
}
Related
This question already has answers here:
Conditionally iterate over one of several possible iterators
(4 answers)
Closed 2 years ago.
I want have something like below
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> impl IntoIterator<Item = i32> {
match self {
DiffStruct::V(vec) => vec.iter().into_iter(),
DiffStruct::M(map) => map.values().into_iter(),
}
}
}
fn main() {
let v: Vec<_> = DiffStruct::V(vec![1,2,3]).to_iter().collect();
}
playground
So that I can minimize the collect behavior of my code for best performance, but it does not compile, any workaround to achieve this?
Assuming you want to take ownership of DiffStruct and not just borrow it when you collect its values:
use std::collections::HashMap;
pub enum DiffStruct {
V(Vec<i32>),
M(HashMap<i32,i32>),
}
impl DiffStruct {
fn to_iter(self) -> Box<dyn Iterator<Item = i32>> {
match self {
DiffStruct::V(vec) => Box::new(vec.into_iter()),
DiffStruct::M(map) => Box::new(map.into_iter().map(|(_, v)| v)),
}
}
}
fn main() {
let vec_values = vec![1, 2, 3];
let mut map_values = HashMap::new();
map_values.insert(1, 1);
map_values.insert(2, 2);
map_values.insert(3, 3);
let ds_vec = DiffStruct::V(vec_values);
let ds_map = DiffStruct::M(map_values);
let collected_from_vec: Vec<_> = ds_vec.to_iter().collect();
let collected_from_map: Vec<_> = ds_map.to_iter().collect();
}
playground
See also
Conditionally iterate over one of several possible iterators
What is the correct way to return an Iterator?
I am trying to find an elegant way to fill a vector of struct elements with a loop or logic instead of writing one .push() for every element I create.
The struct element is a question with many more fields than in the following example and the instances need to be mutable because they are modified by user input :
struct Question {
id: usize,
question: String,
}
fn main() {
//A large and growing list of questions
let mut q0 = Question {
id: 0,
question: String::from("A field I fill in manually"),
};
// .
// .
// .
let mut q100 = Question {
id: 100,
question: String::from("Another field, each one is different"),
};
let total_questions: usize = 100;
let mut w: Vec<String> = Vec::new();
for a in 0..total_questions {
let s = format!("q{}", a);
w.push(s);
}
//w contains ["q0", "q1", ..., "q100"] but is of type std::string::String
let mut v: Vec<&mut Question> = Vec::new();
//Expects type struct `main::Question`
//I would like to avoid :
v.push(&mut q0);
v.push(&mut q1);
// .
// .
// .
v.push(&mut q100);
}
I am not sure that in my example the w: Vec<String> is of any use.
I have looked into .collect() but could not understand how to utilize it in my case.
I'd be happy to be pointed towards a similar question if this is a duplicate I have not found one.
Edit : I have changed the structs string content as it was misleading. They each contain Strings that are unique and cannot be generated. I also realized that Stack Overflow automatically included this in a some_fn() function when we are actually inside main()
The problem is because you don't have any data structure that contains the Questions -- you just have 100+ independent local variables -- it's not possible to iterate over them to fill the Vec. You can fix this by putting all the Questions in a Vec<Question> as you create them. Here's an example:
let mut v: Vec<Question> = vec![
Question {
id: 0,
question: String::from("Q0"),
},
// ...
Question {
id: 100,
question: String::from("Q100"),
},
];
In fact, once you do this you probably don't need the Vec<&mut Question> at all, since you can mutate the questions directly by indexing v. However, if you do need the vector of references for some reason, you can create it by collecting an iterator:
let v_refs: Vec<&mut Question> = v.iter_mut().collect();
If you can generate your Question object with a function you can use an iterator. Here is an example which just generates numbered Question objects out of a numeric range:
struct Question {
id: usize,
question: String,
}
fn main() {
let v: Vec<Question> = (0..10)
.map(|x| Question {
id: x,
question: "Q".to_string() + &x.to_string(),
})
.collect();
for x in &v {
println!("{}: {}", x.id, x.question);
}
}
Here is an example where you get the strings from an array of strings:
struct Question<'a> {
id: usize,
question: &'a str,
}
const QUESTIONS: [&str; 3] = ["A", "B", "C"];
fn main() {
let v: Vec<Question> = (0..questions.len())
.map(|x| Question {
id: x,
question: questions[x],
})
.collect();
for x in &v {
println!("{}: {}", x.id, x.question);
}
}
I can use resize, but it seems like overkill because I do not need to resize the vector, just modify its values. Using a new variable is not an option, since this vector is actually a field in a struct.
I guess that resize is efficient, and probably the answer to my question, but its name does not carry the meaning of resetting the values without modifying the size.
In C, I would use memset (in opposition to realloc).
Illustration of my question:
let my_vec_size = 42;
let mut my_vec = Vec::new(); // 'my_vec' will always have a size of 42
my_vec.resize(my_vec_size, false); // Set the size to 42, and all values to false
// [ ... ] piece of code where the values in 'my_vec' will be modified, checked, etc ...
// now I need to reuse my_vec.
// Possibility A -> use resize again
my_vec.resize(my_vec_size, false);
// Possibility B -> iterate on the vector to modify its values (long and laborious)
for item in my_vec.iter_mut() {
*item = false;
}
// Possibility C ?
The most efficient way in general is to reset the values themselves (aka B):
for item in &mut my_vec { *item = false; }
For booleans it is not immediately obvious, however for a String it is important to preserve the allocated buffer of each element:
for item in &mut my_vec { item.clear(); }
If discarding and recreating the elements of the Vec is cheap, such as the case of the boolean or if the elements will be overwritten anyway, then a combination of clear and resize is easier:
my_vec.clear();
my_vec.resize(my_vec_size, false);
resize by itself will not work to "reset" values:
const LEN: usize = 3;
fn main() {
let mut values = vec![false; LEN];
values[0] = true;
values.resize(LEN, false);
println!("{:?}", values); // [true, false, false]
}
Just use a for loop:
for v in &mut values {
*v = false;
}
println!("{:?}", values); // [false, false, false]
If that sight offends you, write an extension trait:
trait ResetExt<T: Copy> {
fn reset(&mut self, val: T);
}
impl<T: Copy> ResetExt<T> for [T] {
fn reset(&mut self, value: T) {
for v in self {
*v = value;
}
}
}
values.reset(false);
println!("{:?}", values); // [false, false, false]
The trait idea can be extended so that each value knows how to reset itself, if that makes sense for your situation:
trait ResetExt {
fn reset(&mut self);
}
impl<T: ResetExt> ResetExt for [T] {
fn reset(&mut self) {
for v in self {
v.reset();
}
}
}
impl ResetExt for bool {
fn reset(&mut self) {
*self = false;
}
}
impl ResetExt for String {
fn reset(&mut self) {
self.clear();
}
}
values.reset();
println!("{:?}", values); // [false, false, false]
In C, I would use memset
std::ptr::write_bytes uses memset internally, so you can (almost) precisely translate this code. An example from the Rust documentation:
let mut vec = vec![0u32; 4];
unsafe {
let vec_ptr = vec.as_mut_ptr();
ptr::write_bytes(vec_ptr, 0xfe, 2);
}
assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
I understand that the preferred way to iterate in Rust is through the for var in (range) syntax, but sometimes I'd like to work on more than one of the elements in that range at a time.
From a Ruby perspective, I'm trying to find a way of doing (1..100).each_slice(5) do |this_slice| in Rust.
I'm trying things like
for mut segment_start in (segment_size..max_val).step_by(segment_size) {
let this_segment = segment_start..(segment_start + segment_size).iter().take(segment_size);
}
but I keep getting errors that suggest I'm barking up the wrong type tree. The docs aren't helpful either--they just don't contain this use case.
What's the Rust way to do this?
Use chunks (or chunks_mut if you need mutability):
fn main() {
let things = [5, 4, 3, 2, 1];
for slice in things.chunks(2) {
println!("{:?}", slice);
}
}
Outputs:
[5, 4]
[3, 2]
[1]
The easiest way to combine this with a Range would be to collect the range to a Vec first (which dereferences to a slice):
fn main() {
let things: Vec<_> = (1..100).collect();
for slice in things.chunks(5) {
println!("{:?}", slice);
}
}
Another solution that is pure-iterator would be to use Itertools::chunks_lazy:
extern crate itertools;
use itertools::Itertools;
fn main() {
for chunk in &(1..100).chunks_lazy(5) {
for val in chunk {
print!("{}, ", val);
}
println!("");
}
}
Which suggests a similar solution that only requires the standard library:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
for value in range.by_ref().take(5) {
print!("{}, ", value);
}
println!("");
}
}
One trick is that Ruby and Rust have different handling here, mostly centered around efficiency.
In Ruby Enumerable can create new arrays to stuff values in without worrying about ownership and return a new array each time (check with this_slice.object_id).
In Rust, allocating a new vector each time would be pretty unusual. Additionally, you can't easily return a reference to a vector that the iterator holds due to complicated lifetime concerns.
A solution that's very similar to Ruby's is:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
let chunk: Vec<_> = range.by_ref().take(5).collect();
println!("{:?}", chunk);
}
}
Which could be wrapped up in a new iterator that hides the details:
use std::iter::Peekable;
struct InefficientChunks<I>
where I: Iterator
{
iter: Peekable<I>,
size: usize,
}
impl<I> Iterator for InefficientChunks<I>
where I: Iterator
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.iter.peek().is_some() {
Some(self.iter.by_ref().take(self.size).collect())
} else {
None
}
}
}
trait Awesome: Iterator + Sized {
fn inefficient_chunks(self, size: usize) -> InefficientChunks<Self> {
InefficientChunks {
iter: self.peekable(),
size: size,
}
}
}
impl<I> Awesome for I where I: Iterator {}
fn main() {
for chunk in (1..100).inefficient_chunks(5) {
println!("{:?}", chunk);
}
}
Collecting into a vec can easily kill your performance. An approach similar to in the question is perfectly fine.
fn chunk_range(range: Range<usize>, chunk_size: usize) -> impl Iterator<Item=Range<usize>> {
range.clone().step_by(chunk_size).map(move |block_start| {
let block_end = (block_start + chunk_size).min(range.end);
block_start..block_end
})
}
I have a recursive Item structure that I am using to implement lists:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
When implementing a function that inserts an element after another one, I found out that the Rust compiler wasn't that happy about my code:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
The errors that I get are pretty obscure for a newbie:
error[E0382]: use of collaterally moved value: `(it as Item::Cons).1`
--> src/main.rs:12:23
|
12 | Item::Cons(a, b) => {
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because the value has type `T`, which does not implement the `Copy` trait
Another similar question suggested to do the unwrapping phase in two steps but it cannot be used here because we need to directly unwrap a two-fields Cons(..) item and not nested items like Option<Box<Whatever>> where the two-phase trick can be applied. Example of what I tried:
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match *it {
Item::Nil => return it,
Item::Cons(..) => {
let Item::Cons(a, b) = *it;
let itm = Box::new(Item::Cons(val, b));
return Box::new(Item::Cons(a, itm));
}
}
}
But I get another error:
error[E0005]: refutable pattern in local binding: `Nil` not covered
--> src/main.rs:13:17
|
13 | let Item::Cons(a, b) = *it;
| ^^^^^^^^^^^^^^^^ pattern `Nil` not covered
Though I am pretty sure here that this is exhaustive at this point because we matched a Cons before.
You may be suffering from issue 16223 (see also 22205 which has a closer reproduction), although today's non-lexical lifetimes don't solve this problem. This seems to preclude destructuring multiple things through a Box.
Here's one way to work around it, although it's not the most efficient way as it deallocates and reallocates unnecessarily:
#[derive(Debug)]
pub enum Item<T> {
Cons(T, Box<Item<T>>),
Nil,
}
pub fn add_after<T>(it: Box<Item<T>>, val: T) -> Box<Item<T>> {
match { *it } {
Item::Nil => Box::new(Item::Nil),
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
Box::new(Item::Cons(a, itm))
}
}
}
fn main() {}
A more verbose way pulls the value out of the Box, manipulates that, and then puts the manipulated value back into the Box. This should have a reduced amount of allocations:
use std::mem;
pub fn add_after<T>(mut item: Box<Item<T>>, val: T) -> Box<Item<T>> {
let unboxed_value = mem::replace(&mut *item, Item::Nil);
match unboxed_value {
Item::Nil => item,
Item::Cons(a, b) => {
let itm = Box::new(Item::Cons(val, b));
*item = Item::Cons(a, itm);
item
}
}
}
See also:
Collaterally moved error when deconstructing a Box of pairs