Related
I want to call .map() on an array of enums:
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
}
but the compiler complains:
error[E0277]: the trait bound `[Foo; 3]: std::iter::FromIterator<Foo>` is not satisfied
--> src/main.rs:8:51
|
8 | let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
| ^^^^^^^ a collection of type `[Foo; 3]` cannot be built from an iterator over elements of type `Foo`
|
= help: the trait `std::iter::FromIterator<Foo>` is not implemented for `[Foo; 3]`
How do I do this?
The issue is actually in collect, not in map.
In order to be able to collect the results of an iteration into a container, this container should implement FromIterator.
[T; n] does not implement FromIterator because it cannot do so generally: to produce a [T; n] you need to provide n elements exactly, however when using FromIterator you make no guarantee about the number of elements that will be fed into your type.
There is also the difficulty that you would not know, without supplementary data, which index of the array you should be feeding now (and whether it's empty or full), etc... this could be addressed by using enumerate after map (essentially feeding the index), but then you would still have the issue of deciding what to do if not enough or too many elements are supplied.
Therefore, not only at the moment one cannot implement FromIterator on a fixed-size array; but even in the future it seems like a long shot.
So, now what to do? There are several possibilities:
inline the transformation at call site: [Value(1), Value(2), Value(3)], possibly with the help of a macro
collect into a different (growable) container, such as Vec<Foo>
...
Update
This can work:
let array: [T; N] = something_iterable.[into_]iter()
.collect::<Vec<T>>()
.try_into()
.unwrap()
In newer version of rust, try_into is included in prelude, so it is not necessary to use std::convert::TryInto. Further, starting from 1.48.0, array support directly convert from Vec type, signature from stdlib source:
fn try_from(mut vec: Vec<T, A>) -> Result<[T; N], Vec<T, A>> {
...
}
Original Answer
as of rustc 1.42.0, if your element impl Copy trait, for simplicity, this just works:
use std::convert::TryInto;
...
let array: [T; N] = something_iterable.[into_]iter()
.collect::<Vec<T>>()
.as_slice()
.try_into()
.unwrap()
collect as_slice try_into + unwrap()
Iterator<T> ------> Vec<T> -------> &[T] ------------------> [T]
But I would just call it a workaround.
You need to include std::convert::TryInto because the try_into method is defined in the TryInto trait.
Below is the signature checked when you call try_into as above, taken from the source. As you can see, that requires your type T implement Copy trait, so theoritically, it will copy all your elements once.
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
T: Copy,
[T; N]: LengthAtMost32,
{
type Error = TryFromSliceError;
fn try_from(slice: &[T]) -> Result<[T; N], TryFromSliceError> {
<&Self>::try_from(slice).map(|r| *r)
}
}
While you cannot directly collect into an array for the reasons stated by the other answers, that doesn't mean that you can't collect into a data structure backed by an array, like an ArrayVec:
use arrayvec::ArrayVec; // 0.7.0
use std::array;
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos: ArrayVec<_, 3> = array::IntoIter::new(bar).map(Foo::Value).collect();
let the_array = foos
.into_inner()
.unwrap_or_else(|_| panic!("Array was not completely filled"));
// use `.expect` instead if your type implements `Debug`
}
Pulling the array out of the ArrayVec returns a Result to deal with the case where there weren't enough items to fill it; the case that was discussed in the other answers.
For your specific problem, Rust 1.55.0 allows you to directly map an array:
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.map(Foo::Value);
}
In this case you can use Vec<Foo>:
#[derive(Debug)]
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let foos = bar.iter().map(|&x| Foo::Value(x)).collect::<Vec<Foo>>();
println!("{:?}", foos);
}
.collect() builds data structures that can have arbitrary length, because the iterator's item number is not limited in general. (Shepmaster's answer already provides plenty details there).
One possibility to get data into an array from a mapped chain without allocating a Vec or similar is to bring mutable references to the array into the chain. In your example, that'd look like this:
#[derive(Debug, Clone, Copy)]
enum Foo {
Value(i32),
Nothing,
}
fn main() {
let bar = [1, 2, 3];
let mut foos = [Foo::Nothing; 3];
bar.iter().map(|x| Foo::Value(*x))
.zip(foos.iter_mut()).for_each(|(b, df)| *df = b);
}
The .zip() makes the iteration run over both bar and foos in lockstep -- if foos were under-allocated, the higher bars would not be mapped at all, and if it were over-allocated, it'd keep its original initialization values. (Thus also the Clone and Copy, they are needed for the [Nothing; 3] initialization).
You can actually define a Iterator trait extension to do this!
use std::convert::AsMut;
use std::default::Default;
trait CastExt<T, U: Default + AsMut<[T]>>: Sized + Iterator<Item = T> {
fn cast(mut self) -> U {
let mut out: U = U::default();
let arr: &mut [T] = out.as_mut();
for i in 0..arr.len() {
match self.next() {
None => panic!("Array was not filled"),
Some(v) => arr[i] = v,
}
}
assert!(self.next().is_none(), "Array was overfilled");
out
}
}
impl<T, U: Iterator<Item = T>, V: Default + AsMut<[T]>> CastExt<T, V> for U { }
fn main () {
let a: [i32; 8] = (0..8).map(|i| i * 2).cast();
println!("{:?}", a); // -> [0, 2, 4, 6, 8, 10, 12, 14]
}
Here's a playground link.
This isn't possible because arrays do not implement any traits. You can only collect into types which implement the FromIterator trait (see the list at the bottom of its docs).
This is a language limitation, since it's currently impossible to be generic over the length of an array and the length is part of its type. But, even if it were possible, it's very unlikely that FromIterator would be implemented on arrays because it'd have to panic if the number of items yielded wasn't exactly the length of the array.
You may combine arrays map method with Iterator::next.
Example:
fn iter_to_array<Element, const N: usize>(mut iter: impl Iterator<Item = Element>) -> [Element; N] {
// Here I use `()` to make array zero-sized -> no real use in runtime.
// `map` creates new array, which we fill by values of iterator.
let res = [(); N].map(|_| iter.next().unwrap());
// Ensure that iterator finished
assert!(matches!(iter.next(), None));
res
}
I ran into this problem myself — here's a workaround.
You can't use FromIterator, but you can iterate over the contents of a fixed-size object, or, if things are more complicated, indices that slice anything that can be accessed. Either way, mutation is viable.
For example, the problem I had was with an array of type [[usize; 2]; 4]:
fn main() {
// Some input that could come from another function and thus not be mutable
let pairs: [[usize; 2]; 4] = [[0, 0], [0, 1], [1, 1], [1, 0]];
// Copy mutable
let mut foo_pairs = pairs.clone();
for pair in foo_pairs.iter_mut() {
// Do some operation or other on the fixed-size contents of each
pair[0] += 1;
pair[1] -= 1;
}
// Go forth and foo the foo_pairs
}
If this is happening inside a small function, it's okay in my book. Either way, you were going to end up with a transformed value of identical type as the same one, so copying the whole thing first and then mutating is about the same amount of effort as referencing a value in a closure and returning some function of it.
Note that this only works if you plan to compute something that is going to be the same type, up to and including size/length. But that's implied by your use of Rust arrays. (Specifically, you could Value() your Foos or Nothing them as you like, and still be within type parameters for your array.)
I couldn't find a simple thing on google. How to convert a simple Rust array to a pointer?
How to get pointer to [u8; 3]? I tried doing as *mut u8 but it wouldn't work.
Use as_ptr() or as_mut_ptr().
fn main() {
let a: [u8; 3] = [1, 2, 3];
println!("{:p}", a.as_ptr());
}
0x7ffc97350edd
Arrays coerce to slices, so any slice method may be called on an array.
Note that arrays in Rust are just blobs of memory. They does not point on some stored objects, like an arrays in C do, they are a sequence of objects.
If you have some data and want to get a pointer to it, you'll usually create a reference instead, since only references (and other pointers) can be cast to pointers with as:
fn main() {
let a: [u8; 3] = [1, 2, 3]; // a blob of data on the stack...
let a_ref = &a; // a shared reference to this data...
let a_ptr = a_ref as *const u8; // and a pointer, created from the reference
println!("{:p}", a_ptr);
}
Playground
Raw idea
In a dummy project I have, I would like to use cycling iterators (to generate integers for example).
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2].iter().cycle(),
[2, 4].iter().cycle(),
];
cycles
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
Refactor
Although the previous piece of code works as intended, my real world example is a bit more complicated, so I am looking to adapt the generate_cycles function to be able to perform more operations (in the following example, multiply by 2, then generate the cycling iterators).
For this, I tried to use arraymap:
extern crate arraymap;
use arraymap::ArrayMap;
use std::iter::Cycle;
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let mut cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.iter().cycle()
})
}
fn main() {
let mut cycles = generate_cycles();
// ...
}
The problem
The above solution does not work, and, as a Rust beginner recently exposed to the concept of "lifetime", I do not understand why the compiler is complaining here, or what I can do to make him happy.
error[E0495]: cannot infer an appropriate lifetime for autorefdue to conflicting requirements
--> src/main.rs:20:14
|
20 | points.iter().cycle()
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 19:10...
--> src/main.rs:19:10
|
19 | .map(|points| {
| __________^
20 | | points.iter().cycle()
21 | | })
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:20:7
|
20 | points.iter().cycle()
| ^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected [std::iter::Cycle<std::slice::Iter<'static, i32>>; 2]
found [std::iter::Cycle<std::slice::Iter<'_, i32>>; 2]
Here is a REPL with the code trying to make use of the arraymap: https://repl.it/repls/ShadowyStrikingFirm .
In your type declaration:
type IntegerCycle = Cycle<std::slice::Iter<'static, i32>>;
You say that you the underlying slices you use to build your iterators must have 'static lifetime, that is, they must live forever. Then you use literal arrays such as [1, 2] that, as all literals, have 'static' lifetime and all goes well:
let r: &'static [i32; 2] = &[1, 2]; //Ok
But then, you try a code similar to this simpler one:
let a = [1, 2].map(|x| 2 * x);
let r: &'static [i32; 2] = &a; //error: borrowed value does not live long enough
That is the result of arraymap::map is a normal array, not a literal one, so it does not have a 'static lifetime. It cannot be static because you are computing the values in runtime. It will live as long as necessary, in my case as long as the variable a.
In your case, since the returns of arraymap::map are not assigned to variables, they are temporary values and they are quickly dropped. But even if you assigned it to a local variable, you could not return a reference to it, because the local variable is dropped when the function ends.
The solution is to return an iterator that owns the value. Something like this works:
type IntegerCycle = Cycle<std::vec::IntoIter<i32>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
points.to_vec().into_iter().cycle()
})
}
Unfortunately you have to use a Vec instead of an array, because there is not an IntoIterator implementation for arrays, (there are for slices, but they do not own the values).
If you want to avoid the extra allocation of Vec you can use the arrayvec crate that does allow to take an iterator to an array:
type IntegerCycle = Cycle<arrayvec::IntoIter<[i32; 2]>>;
fn generate_cycles() -> [IntegerCycle; 2] {
let cycles = [
[1, 2],
[2, 4],
];
cycles
.map(|points| {
points.map(|point| point*2)
})
.map(|points| {
let a = arrayvec::ArrayVec::from(*points);
a.into_iter().cycle()
})
}
NOTE: It looks like there is an attempt to add a proper IntoIterator impl for arrays by value to the std, but there are still some pending issues.
As the title reads, how would I go about doing this?
fn foo(array: &[u32; 10]) -> &[u32; 5] {
&array[0..5]
}
Compiler error
error[E0308]: mismatched types
--> src/main.rs:2:5
|
2 | &array[0..5]
| ^^^^^^^^^^^^ expected array of 5 elements, found slice
|
= note: expected type `&[u32; 5]`
= note: found type `&[u32]`
arrayref implements a safe interface for doing this operation, using macros (and compile-time constant slicing bounds, of course).
Their readme explains
The goal of arrayref is to enable the effective use of APIs that involve array references rather than slices, for situations where parameters must have a given size.
and
let addr: &[u8; 16] = ...;
let mut segments = [0u16; 8];
// array-based API with arrayref
for i in 0 .. 8 {
segments[i] = read_u16_array(array_ref![addr,2*i,2]);
}
Here the array_ref![addr,2*i,2] macro allows us to take an array reference to a slice consisting of two bytes starting at 2*i. Apart from the syntax (less nice than slicing), it is essentially the same as the slice approach. However, this code makes explicit the need for precisely two bytes both in the caller, and in the function signature.
Stable Rust
It's not possible to do this using only safe Rust. To understand why, it's important to understand how these types are implemented. An array is guaranteed to have N initialized elements. It cannot get smaller or larger. At compile time, those guarantees allow the size aspect of the array to be removed, and the array only takes up N * sizeof(element) space.
That means that [T; N] and [T; M] are different types (when N != M) and you cannot convert a reference of one to the other.
The idiomatic solution is to use a slice instead:
fn foo(array: &[u32; 10]) -> &[u32] {
&array[0..5]
}
A slice contains a pointer to the data and the length of the data, thus moving that logic from compile time to run time.
Nightly Rust
You can perform a runtime check that the slice is the correct length and convert it to an array in one step:
#![feature(try_from)]
use std::convert::TryInto;
fn foo(array: &[u32; 10]) -> &[u32; 5] {
array[0..5].try_into().unwrap()
}
fn main() {}
Unsafe Rust
Because someone might want to do this the unsafe way in an earlier version of Rust, I'll present code based on the standard library implementation:
fn foo(array: &[u32; 10]) -> &[u32; 5] {
let slice = &array[0..5];
if slice.len() == 5 {
let ptr = slice.as_ptr() as *const [u32; 5];
unsafe { &*ptr }
} else {
panic!("Needs to be length 5")
}
}
fn main() {
let input = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let output = foo(&input);
println!("{:?}", output);
}
Can someone explain why this compiles:
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a[4]);
}
When running it, I got:
thread '' panicked at 'index out of bounds: the len is 3 but the index is 4', ../src/libcollections/vec.rs:1132
If you would like to access elements of the Vec with index checking, you can use the Vec as a slice and then use its get method. For example, consider the following code.
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a.get(2));
println!("{:?}", a.get(4));
}
This outputs:
Some(3)
None
In order to understand the issue, you have to think about it in terms of what the compiler sees.
Typically, a compiler never reasons about the value of an expression, only about its type. Thus:
a is of type Vec<i32>
4 is of an unknown integral type
Vec<i32> implements subscripting, so a[4] type checks
Having a compiler reasoning about values is not unknown, and there are various ways to get it.
you can allow evaluation of some expression at compile-time (C++ constexpr for example)
you can encode value into types (C++ non-type template parameters, using Peano's numbers)
you can use dependent typing which bridges the gap between types and values
Rust does not support any of these at this point in time, and while there has been interest for the former two it will certainly not be done before 1.0.
Thus, the values are checked at runtime, and the implementation of Vec correctly bails out (here failing).
Note that the following is a compile time error:
fn main() {
let a = [1, 2, 3];
println!("{:?}", a[4]);
}
error: this operation will panic at runtime
--> src/main.rs:3:22
|
3 | println!("{:?}", a[4]);
| ^^^^ index out of bounds: the length is 3 but the index is 4
|
= note: `#[deny(unconditional_panic)]` on by default
This works because without the vec!, the type is [i32; 3], which does actually carry length information.
With the vec!, it's now of type Vec<i32>, which no longer carries length information. Its length is only known at runtime.
Maybe what you mean is :
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", a[4]);
}
This returns an Option so it will return Some or None. Compare this to:
fn main() {
let a = vec![1, 2, 3];
println!("{:?}", &a[4]);
}
This accesses by reference so it directly accesses the address and causes the panic in your program.