I am really new in rust, and while going through the rustlings exercises I found something I do not fully understand regarding stacked Options.
Given the following code:
let vector = vec![Some(24), None, Some(42)];
let mut iter = vector.iter();
while let Some(Some(number)) = iter.next() {
println!("Number: {}", number);
}
I would expect to see the following output:
Number: 24
Number: 42
But I guess as soon as rust encounters the None, the while loop exits, only printing the 24
What would be the most idiomatic rust code to iterate and unwrap optional values?
The closest that I got would look something like this:
let mut iter = vector.iter();
while let Some(iterNext) = iter.next() {
if let Some(num) = iterNext {
println!("Number: {}", num);
}
}
Or it could also be done by checking the existence in a for loop:
for opt in &vector {
if opt.is_some() {
println!("Number: {}", opt.unwrap());
}
}
Another nice way to write this code is
for num in vector.iter().flatten() {
println!("{}", num);
}
The flatten() method on an iterator treats each item of the iterator as an iterator, and returns an iterator over all these iterators chained together. Option is an iterator that yields one element if it is Some, or none for None, so flatten() is exactly what we want here.
Of course you could also write this using for_each(), but for code with side effects I generally prefer for loops.
I would expect to see the following output: [...]
A while loop that encounters a false condition exits - but that's not specific to Rust, it's just how while loops work.
An idiomatic solution would probably combine your last two snippets:
for opt in &vector {
if let Some(num) = opt {
println!("Number: {}", num);
}
}
Just a simple for loop containing an if let, no unwrapping required.
Another idiomatic variant is to use iterator adapters:
vector
.iter()
.filter_map(|opt| opt.as_ref())
.for_each(|num| println!("{}", num));
Note that here we could use filter(Option::is_some), but then we would be left with options and would have to use unwrap() to get to the values. This is where
filter_map() comes in useful: it filters the Some values (after applying the map function), and at the same time extracts the values inside. opt.as_ref() serves to trivially convert &Option<T>, obtained from iterating a vector of options by reference, to Option<&T> which filter_map expects returned.
Using and_then to filter out the None's and only delivering Some's to the programs working part:
let vector = vec![Some(24), None, Some(42)];
for num in vector.iter() {
num.and_then::<i32, fn(i32) -> Option<i32>>(|n| {
println!("{}", n); // …working part
None
});
}
Related
I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:
let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?
Yes, this is easy with unsafe; is there a way to do it without unsafe?
As of Rust 1.38 (released in September 2019), a cleaner alternative to previously posted answers is possible using an intermediate const initializer. This approach works for arrays of any size:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(It works with or without the Box; the example uses Box because it was used in the question.)
One limitation is that the array item must have a default representation that can be evaluated at compile time - a constant, enum variant, or a primitive container composed of those. None or a tuple of numbers will work, but a non-empty Vec or String won't.
You could use the Default trait to initialize the array with default values:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
See this playground for a working example.
Note that this will only work for arrays with up to 32 elements, because Default::default is only implemented for up to [T; 32]. See https://doc.rust-lang.org/std/default/trait.Default.html#impl-Default-for-%5BT%3B%2032%5D.
As of Rust 1.55.0 (which introduced [T]::map()), the following will work:
const SIZE: usize = 100;
#[derive(Debug)]
struct THING { data: i64 }
let array = [(); SIZE].map(|_| Option::<THING>::default());
for x in array {
println!("x: {:?}", x);
}
Rust Playground
I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.
Go through the heap
If you can create a Vec of your type, you can convert it into an array:
use std::convert::TryInto;
#[derive(Clone)]
struct Thing;
const SIZE: usize = 100;
fn main() {
let v: Vec<Option<Thing>> = vec![None; SIZE];
let v: Box<[Option<Thing>; SIZE]> = match v.into_boxed_slice().try_into() {
Ok(v) => v,
Err(_) => unreachable!(),
};
let v: [Option<Thing>; SIZE] = *v;
}
In many cases, you actually want to leave it as a Vec<T>, Box<[T]>, or Box<[T; N]> as these types all put the data in the heap. Large arrays tend to be... large... and you don't want all that data on the stack.
See also:
What is the use of into_boxed_slice() methods?
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Keep it simple
Type out all the values:
struct Thing;
const SIZE: usize = 5;
fn main() {
let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}
You could use a build script to generate this code for you. For an example of this, see:
How to create a static string at compile time
An alternative approach using the arrayvec crate that generalizes easily to situations other than initializing everything with a fixed value:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();
(playground)
On nightly Rust, you can use inline const. This is a variant of the answer by #user4815162342, but one that doesn't require you to declare a separate constant and repeat the type:
#![feature(inline_const)]
let array: [Option<Box<Thing>>; SIZE] = [const { None }; SIZE];
Until this is stabilized (hopefully soon), you can also use the inline-const crate, but this does require you to repeat the type.
let stackoverflow: [Option<&mut ()>;0xDEADBEEF] = std::array::from_fn(|_| None);
dbg!(stackoverflow);
playground
I have an iterator full of u8's that I want to write to a file or stdout. Calling io::stdout().write_all(foo) on my iterator gives me an expected type &[u8], and that I have an iterator type instead. I understand why this doesn't work.
What I don't understand is how to change it so that it does work. At first I tried adding a .collect() to the end of my iterator, but then it says the trait bound &[u8]: std::iter::FromIterator<u8> is not satisfied and a collection of type &[u8] cannot be built from an iterator over elements of type u8.
It seems odd to me that Write doesn't provide a way of writing with an iterator, when Read provides a bytes() function that returns an iterator. What is the idiomatic way to do this?
Here is my main function's contents:
io::stdout().write_all(
io::stdin().bytes().map(
|x| match x {
Ok(b) => b,
_ => panic!("There was an error reading from stdin"),
}
).repeat(3).collect()
);
It seems odd to me that Write doesn't provide a way of writing with an iterator, when Read provides a bytes() function that returns an iterator. What is the idiomatic way to do this?
It does feel inconsistent, indeed, but you can certainly write the equivalent yourself.
Something like:
fn write_all<W: Write, I: Iterator<Item=u8>>(writer: &mut W, iter: I) {
const SIZE: usize = 1024;
let mut buffer = [0u8; SIZE];
let mut index = 0;
for i in iter {
buffer[index] = i;
index += 1;
if index == SIZE {
writer.write_all(&buffer);
}
}
writer.write_all(&buffer[..index]);
}
There are probably ways to make it more idiomatic, and I haven't tested the boundary conditions, but hopefully it should get you going.
The problem is that you want to build a Vec<u8>, but are attempting to create a Vec<&u8>. You can do the following:
fn main() {
let array = [1u8, 2, 3];
let vector: Vec<u8> = array.iter().map(|i| *i).collect();
}
Note the .map(|i| *i) part that allows to go from &u8 references to u8 values.
This question already has an answer here:
Lifetime of variables passed to a new thread
(1 answer)
Closed 6 years ago.
Take this simple example where we're using an immutable list of vectors to calculate new values.
Given this working, single threaded example:
use std::collections::LinkedList;
fn calculate_vec(v: &Vec<i32>) -> i32 {
let mut result: i32 = 0;
for i in v {
result += *i;
}
return result;
}
fn calculate_from_list(list: &LinkedList<Vec<i32>>) -> LinkedList<i32> {
let mut result: LinkedList<i32> = LinkedList::new();
for v in list {
result.push_back(calculate_vec(v));
}
return result;
}
fn main() {
let mut list: LinkedList<Vec<i32>> = LinkedList::new();
// some arbitrary values
list.push_back(vec![0, -2, 3]);
list.push_back(vec![3, -4, 3]);
list.push_back(vec![7, -10, 6]);
let result = calculate_from_list(&list);
println!("Here's the result!");
for i in result {
println!("{}", i);
}
}
Assuming calculate_vec is a processor intensive function, we may want to use multiple threads to run this, the following example works but requires (what I think is) an unnecessary vector clone.
use std::collections::LinkedList;
fn calculate_vec(v: &Vec<i32>) -> i32 {
let mut result: i32 = 0;
for i in v {
result += *i;
}
return result;
}
fn calculate_from_list(list: &LinkedList<Vec<i32>>) -> LinkedList<i32> {
use std::thread;
let mut result: LinkedList<i32> = LinkedList::new();
let mut join_handles = LinkedList::new();
for v in list {
let v_clone = v.clone(); // <-- how to avoid this clone?
join_handles.push_back(thread::spawn(move || calculate_vec(&v_clone)));
}
for j in join_handles {
result.push_back(j.join().unwrap());
}
return result;
}
fn main() {
let mut list: LinkedList<Vec<i32>> = LinkedList::new();
// some arbitrary values
list.push_back(vec![0, -2, 3]);
list.push_back(vec![3, -4, 3]);
list.push_back(vec![7, -10, 6]);
let result = calculate_from_list(&list);
println!("Here's the result!");
for i in result {
println!("{}", i);
}
}
This example works, but it only when the vector is cloned,
however logically, I don't think this should be needed since the vector is immutable.
There is no reason each call to calculate_vec should need to allocate a new vector.
How could this simple example be multi-threaded without needing to clone the data before its passed to the closure?
Update, heres a working example that uses Arc based on #ker's suggestion, although it does need to take ownership.
Note 1) I'm aware there are 3rd party libraries to handle threading, but would be interested to know if this is possible using Rust's standard library.
Note 2) There are quite a few similar questions on threading but examples often involves threads writing to data, which isn't the case here.
There are multiple ways to solve your problem.
move the Vector into an Arc<LinkedList<Vec<i32>>> and clone that. After the calculation, you can use try_unwrap to get your LinkedList<Vec<i32>> back. This works with just the Rust standard library.Heres a working example that uses Arc, though LinkedList was replaced by Vec to allow indexing.Also note that the function needs to own the argument being passed to it in this case.
Use the crossbeam crate to create threads that can reference their scope, freeing you from the need to do all that join_handles code by hand. This will have a minimal impact on your code, since it work exactly like you want.
crossbeam::scope(|scope| {
for v in list {
scope.spawn(|| calculate_vec(&v))
}
});
Use the scoped_threadpool crate. It works just like crossbeam but doesn't create one thread per task, instead it spreads out the tasks over a limited number of threads. (thanks #delnan)
use the rayon crate for direct data parallelism
use rayon::prelude::*;
list.par_iter().map(|v| calculate_vec(&v)).collect()
I've tried using &str instead of String, but that has compilation errors. I ended up with:
fn main()
{
let words: Vec<String> = vec!["apple".to_string(), "orange".to_string(), "banana".to_string()];
let word: String = match words.get(4)
{
Some(s) => s.to_string()
, None => "nil".to_string()
};
println!("word: {}", word);
}
There are two things that will immediately help shorten this program:
Type inference: you very rarely have to write types out
&str: way too many calls to to_string here
I would write it as:
fn main() {
let words = vec!["apple", "orange", "banana"];
let word = match words.get(4) {
Some(&s) => s,
None => "nil"
};
println!("word: {}", word);
}
Note that Vec<T>::get returns an Option<&T>, thus here an Option<&&str>, since we want s to be of type &str (single &), we use Some(&s) as the pattern. Another option would be Some(s) => *s, (here, having s be &&str and dereferencing it).
Of course, this can all be further reduced by looking at the specific API of Option. Somewhat less universal, but Option and Result are very often used in Rust (so much they are in the prelude!!!) and therefore it's worth learning their APIs.
In this case unwrap_or will provide either the value inside Option or the value passed to it:
fn main() {
let words = vec!["apple", "orange", "banana"];
let word = *words.get(4).unwrap_or(&"nil");
println!("word: {}", word);
}
Bit of reference juggling to line-up the types (aka type Tetris) and it's all good.
I'm not exactly sure, what you want to achieve, but this is probably the best way to do exactly what you did in your code:
fn main() {
let words = vec!["apple", "orange", "banana"];
let word = words.get(4).cloned().unwrap_or("nil").to_string();
println!("word: {}", word);
}
The tricky part is cloned(): the get() method will return an optional reference to the value inside of the vector. But since the vector already holds references, we end up with Option<&&str> (two references). The cloned() call removes one reference, thus we have Option<&str>.
Also note that in this example the final to_string() call isn't necessary -- we can do everything only with &str.
It is important to remember the coercion rules of strings when deciding between &str and String.
fn main()
{
let words = vec!["apple", "orange", "banana"]; // Vec<&str>
let word = match words.get(2) { // &str
Some(&s) => s
None => "nil"
};
println!("word: {}", word);
}
You could consolidate the words and word matching code if length was still a concern for you, but I think this (perhaps including type annotations) is the most succinct without compromising clarity.
I’m trying to initialize a fixed-size array of some nullable, non-copyable type, like an Option<Box<Thing>> for some kind of Thing. I’d like to pack two of them into a struct without any extra indirection. I’d like to write something like this:
let array: [Option<Box<Thing>>; SIZE] = [None; SIZE];
But it doesn’t work because the [e; n] syntax requires that e implements Copy. Of course, I could expand it into SIZE Nones, but that can be unwieldy when SIZE is large. I don’t believe this can be done with a macro without an unnatural encoding of SIZE. Is there a good way to do it?
Yes, this is easy with unsafe; is there a way to do it without unsafe?
As of Rust 1.38 (released in September 2019), a cleaner alternative to previously posted answers is possible using an intermediate const initializer. This approach works for arrays of any size:
const SIZE: usize = 100;
const INIT: Option<Box<Thing>> = None;
let array: [Option<Box<Thing>>; SIZE] = [INIT; SIZE];
(It works with or without the Box; the example uses Box because it was used in the question.)
One limitation is that the array item must have a default representation that can be evaluated at compile time - a constant, enum variant, or a primitive container composed of those. None or a tuple of numbers will work, but a non-empty Vec or String won't.
You could use the Default trait to initialize the array with default values:
let array: [Option<Box<Thing>>; SIZE] = Default::default();
See this playground for a working example.
Note that this will only work for arrays with up to 32 elements, because Default::default is only implemented for up to [T; 32]. See https://doc.rust-lang.org/std/default/trait.Default.html#impl-Default-for-%5BT%3B%2032%5D.
As of Rust 1.55.0 (which introduced [T]::map()), the following will work:
const SIZE: usize = 100;
#[derive(Debug)]
struct THING { data: i64 }
let array = [(); SIZE].map(|_| Option::<THING>::default());
for x in array {
println!("x: {:?}", x);
}
Rust Playground
I'm copying the answer by chris-morgan and adapting it to match the question better, to follow the recommendation by dbaupp downthread, and to match recent syntax changes:
use std::mem;
use std::ptr;
#[derive(Debug)]
struct Thing {
number: usize,
}
macro_rules! make_array {
($n:expr, $constructor:expr) => {{
let mut items: [_; $n] = mem::uninitialized();
for (i, place) in items.iter_mut().enumerate() {
ptr::write(place, $constructor(i));
}
items
}}
}
const SIZE: usize = 50;
fn main() {
let items = unsafe { make_array!(SIZE, |i| Box::new(Some(Thing { number: i }))) };
println!("{:?}", &items[..]);
}
Note the need to use unsafe here: The problem is that if the constructor function panic!s, this would lead to undefined behavior.
Go through the heap
If you can create a Vec of your type, you can convert it into an array:
use std::convert::TryInto;
#[derive(Clone)]
struct Thing;
const SIZE: usize = 100;
fn main() {
let v: Vec<Option<Thing>> = vec![None; SIZE];
let v: Box<[Option<Thing>; SIZE]> = match v.into_boxed_slice().try_into() {
Ok(v) => v,
Err(_) => unreachable!(),
};
let v: [Option<Thing>; SIZE] = *v;
}
In many cases, you actually want to leave it as a Vec<T>, Box<[T]>, or Box<[T; N]> as these types all put the data in the heap. Large arrays tend to be... large... and you don't want all that data on the stack.
See also:
What is the use of into_boxed_slice() methods?
How to get a slice as an array in Rust?
How do I get an owned value out of a `Box`?
Keep it simple
Type out all the values:
struct Thing;
const SIZE: usize = 5;
fn main() {
let array: [Option<Box<Thing>>; SIZE] = [None, None, None, None, None];
}
You could use a build script to generate this code for you. For an example of this, see:
How to create a static string at compile time
An alternative approach using the arrayvec crate that generalizes easily to situations other than initializing everything with a fixed value:
use arrayvec::ArrayVec;
let array = std::iter::repeat(None)
.take(SIZE)
.collect::<ArrayVec<Option<Box<Thing>>, SIZE>>()
.into_inner()
.unwrap();
(playground)
On nightly Rust, you can use inline const. This is a variant of the answer by #user4815162342, but one that doesn't require you to declare a separate constant and repeat the type:
#![feature(inline_const)]
let array: [Option<Box<Thing>>; SIZE] = [const { None }; SIZE];
Until this is stabilized (hopefully soon), you can also use the inline-const crate, but this does require you to repeat the type.
let stackoverflow: [Option<&mut ()>;0xDEADBEEF] = std::array::from_fn(|_| None);
dbg!(stackoverflow);
playground