Implementing inner type's traits on outer type - struct

With the struct:
struct U85 (
[u8; 5]
);
I get the error:
error[E0608]: cannot index into a value of type `&U85`
--> /home/fadedbee/test.rs:11:40
|
11 | s.serialize_bytes(&self[..])
|
whereas when I use the simple type [u8; 5] everything is fine.
What trait of [u8; 5] causes the indexing error?
How can I implement it for U85?

The x[y] syntax is implemented with the Index and IndexMut traits. One catch with indexing for slices is that x, x..y, .., ..y, x.. are all different types. You can either pick-and-choose what you want to support, but if you just want to do what slices can do, you can implement it like so:
use std::ops::Index;
use std::slice::SliceIndex;
struct U85([u8; 5]);
impl<I> Index<I> for U85 where I: SliceIndex<[u8]> {
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
&self.0[index]
}
}
If you find yourself implementing traits for wrapper types a lot, you can look into using the derive_more crate, which will allow you to derive traits (like Index) that defer to the inner type.
use derive_more::Index;
#[derive(Index)]
struct U85([u8; 5]);

Related

How to use map function to collect an array of string? [duplicate]

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.)

Iterator vs IntoIterator for flatten

I'm playing around with iterators and I've been using Flatten to better understand how iterators work. This example:
assert_eq!(vec![1, 2].iter().flatten().count(), 2);
Does not compile and gives the error (well the primary error of concern):
error[E0277]: `&{integer}` is not an iterator
--> src/lib.rs:59:38
|
59 | assert_eq!(vec![1, 2].iter().flatten().count(), 2);
| ^^^^^^^ `&{integer}` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `&{integer}`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `&{integer}`
What confuses me is that it looks like Flatten requires the nested Item to implement IntoIterator. I confirmed this in the rustdocs, where they declare
pub struct Flatten<I>
where
I: Iterator,
<I as Iterator>::Item: IntoIterator
Just from ready the docs, IntoIterator just provides a way to define how a type is converted into an iterator. Why couldn't the trait bound be <I as Iterator>::Item: Iterator? Surely if the nested item implements Iterator, then we get the same Flatten since the nested item's must be iterators themselves. What difference/benefit does it bring to use IntoIterator instead?
Requiring IntoIterator rather than Iterator lets you flatten a collection of collections in addition to a collection of iterators.
The collection type, for example Vec, is different from the iterator type, so if flatten required the items to be Iterators you couldn't flatten a Vec of Vecs.
IntoIterator represents a type that can be converted into an iterator, such as a Vec or many other collections (or an iterator!). So this, for example, works:
fn main() {
let nested_vec: Vec<Vec<i32>> = vec![vec![1, 2], vec![3, 4]];
let flat_vec: Vec<i32> = nested_vec.into_iter().flatten().collect();
println!("{:?}", flat_vec);
}
You can try this example on the Playground. Using into_iter() above instead of iter() makes sure we iterate over i32s, not references to i32s. (Thanks Cerberus for suggesting into_iter() instead of copied().)
(You can see a few more types with IntoIterator implementations in the docs' "Implementations on Foreign Types" section.)

Cannot infer type for type parameter `S` when using HashSet::from_iter

I am trying to solve an online challenge that involves comparing two sets. I followed this answer to convert my Vec<i32> output to HashSet
use std::collections::HashSet;
use std::iter::FromIterator;
struct Solution {}
impl Solution {
pub fn solve(nums: Vec<i32>, k: i32) -> Vec<i32> {
// todo, return dummy for now
return vec![1, 2];
}
}
fn main() {
assert_eq!(
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2i32])
)
}
For reasons I don't understand yet, the compilation fails:
error[E0282]: type annotations needed
--> src/main.rs:15:9
|
15 | HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
It works fine for HashSet::from_iter(vec![1i32, 2i32])
I tried adding a type annotation like HashSet::from_iter::<Vec<i32>> with no avail. I also read the source implementation but still can't figure out what makes the compiler complain.
I can work around it by declaring it explicitly or construct the HashSet with a for loop and inserts, but I would like to understand what is going on here.
I'm using Rust 1.43.1.
I believe the answer from Kitsu is subtly incorrect since it suggests that Rust cannot infer the type of T because here may be an iterator implemented for a type P that collects a different type T (more on this at the end).
What's really happening
In fact, type inference for type S in HashSet<T, S> has nothing to do with the type of T. The issue is that there is no information in your program that allows the compiler to infer the type of S.
It is correct that adding a type parameter is sufficient to resolve the ambiguity:
HashSet::<i32>::from_iter(vec![1, 2, 3]);
This has nothing to do with the actual type you specify. Indeed, this works as well:
HashSet::<_>::from_iter(vec![1, 2, 3]);
The reason is that the definition of HashSet in the standard library includes a default type for S:
pub struct HashSet<T, S = RandomState> {
base: base::HashSet<T, S>,
}
By writing HashSet::<_>::from_iter(vec![1, 2, 3]); you're telling the compiler that it should use the default type for S, which is RandomState.
What about multiple implementations?
Kitsu's answer states that type inference fails for S because there might be multiple implementations of FromIterator. This is incorrect, but having multiple implementations can cause type inference to fail for T.
Consider this example:
fn iterator_demo() {
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
struct Empty;
impl<T, S> FromIterator<Empty> for HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
{
fn from_iter<I>(iter: I) -> HashSet<T, S>
where
I: IntoIterator<Item = Empty>,
{
iter.into_iter().for_each(drop);
HashSet::default()
}
}
let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
}
This causes type inference to fail; note that this is a failure to infer T, not S:
error[E0282]: type annotations needed for `HashSet<T>`
--> src/lib.rs:22:13
|
22 | let x = HashSet::<_>::from_iter(vec![Empty, Empty]);
| - ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
| |
| consider giving `x` the explicit type `HashSet<T>`, with the type parameters specified
Specifying the type resolves this ambiguity:
let x = HashSet::<String>::from_iter(vec![Empty, Empty]);
Credit to matt1992 on the Rust Discord for helping me to understand what's really happening here.
Let's look at the FromIterator::from_iter declaration, you've been using:
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A>,
After specifying HashSet compiler can deduce that Self is HashSet<S> for some S. T for your particular case can be deduced as a Vec<i32>: IntoIterator<Item = i32> (for the second line that is resolved after you explicitly specified an integer type).
But still, S is not deduced because, in general, you may have an implementation that collects HashSet<u64> from IntoIterator<Item = u8>. So compiler cannot understand what are items of the collected type. Then if you swap the expressions of the assert_eq error source changes:
assert_eq!(
HashSet::from_iter(vec![1i32, 2i32]),
/*
|
15 | HashSet::from_iter(vec![1i32, 2i32]),
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashSet`
*/
HashSet::from_iter(Solution::solve(vec![1, 2, 3], 2)),
)
The solution is fairly straightforward: you need to specify the item type of your HashSet:
assert_eq!(
HashSet::<i32>::from_iter(Solution::solve(vec![1, 2, 3], 2)),
HashSet::from_iter(vec![1i32, 2])
)

What is the proper way to coerce an iterator to return a value instead of a reference (or vice versa)?

The general setup is I have an array of values I'd like to map() and then chain() with 1 additional value. I've learned from this answer that the proper way to construct that final value is to use std::iter::once. This works and eliminated the below problem, but I would still like to understand it better.
In my broken, likely rust-anti-pattern-riddled example, I was using an array of a single element and then calling into_iter(). This produced a value / reference type-mismatch in the chain.
Question: What is the Rust-idiomatic mechanism for correcting this value / reference mismatch? Particularly if clone and copy are unavailable.
Background: Why is there a type mis-match to begin with?
This much I believe I understand. Based on the definition of std::iter::Map, the item type for the iterator is type Item = B where B is constrained by F: FnMut(<I as Iterator>::Item) -> B (i.e. the mapped type). However array defines the following 2 IntoIterator implementations, both of which appear to produce references.
impl<'a, const N: usize, T> IntoIterator for &'a [T; N] where
[T; N]: LengthAtMost32,
type Item = &'a T
impl<'a, const N: usize, T> IntoIterator for &'a mut [T; N] where
[T; N]: LengthAtMost32,
type Item = &'a mut T
Example demonstrating the issue:
#[derive(PartialEq, Eq, Clone, Copy)]
enum Enum1 {
A, B, C
}
#[derive(PartialEq, Eq, Clone, Copy)]
enum Enum2 {
X, Y, Z
}
struct Data {
// Other data omitted
e1: Enum1,
e2: Enum2
}
struct Consumer {
// Other data omitted
/** Predicate which evaluates if this consumer can consume given Data */
consumes: Box<dyn Fn(&Data) -> bool>
}
fn main() {
// Objective: 3 consumers which consume data with A, B, and X respectively
let v: Vec<Consumer> = [Enum1::A, Enum1::B].iter()
.map(|&e1| Consumer { consumes: Box::new(move |data| data.e1 == e1) })
// This chain results in an iterator type-mismatch:
// expected &Consumer, found Consumer
.chain([Consumer { consumes: Box::new(move |data| data.e2 == Enum2::X) }].into_iter())
.collect(); // Fails as well due to the chain failure
}
Error:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, Consumer> as std::iter::IntoIterator>::Item == Consumer`
--> src/main.rs:52:10
|
52 | .chain([Consumer { consumes: Box::new(move |data| data.e2 == Enum2::X) }].into_iter())
| ^^^^^ expected reference, found struct `Consumer`
|
= note: expected type `&Consumer`
found type `Consumer`
Rust playground example.
There is a long-standing issue regarding this. The technical details are a bit heavy, but essentially, due to underlying, technical reasons, you cannot take ownership of a fixed-size array and return owned references without a lot of hocus pocus. This becomes obvious when you think about what a fixed-size array is and how it is stored in memory, and how you can get elements out without cloning them.
As a result, due to the implementations you found already, you can only get borrowed references. You can bypass this with arrayvec (as they have a sound implementation of IntoIterator for ArrayVec with owned types), or you can require that all your T: Clone and deal with it that way, at a cost of extra items in memory (temporarily; 90% of the time the compiler optimizes this away).

Array cannot be indexed by RangeFull?

Consider the following example:
use std::ops::Index;
use std::ops::RangeFull;
fn f<T: Index<RangeFull>>(x: T) {}
fn main() {
let x: [i32; 4] = [0, 1, 2, 3];
f(x);
}
Upon calling f(x), I get an error:
error[E0277]: the type `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
--> src/main.rs:8:5
|
8 | f(x);
| ^ `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
|
= help: the trait `std::ops::Index<std::ops::RangeFull>` is not implemented for `[i32; 4]`
note: required by `f`
--> src/main.rs:4:1
|
4 | fn f<T: Index<RangeFull>>(x: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I am confused. I can obviously write, for example, let y = x[..];. Does this not mean indexing x with RangeFull? Are arrays somehow special in this regard?
As you can see in the documentation for the primitive array type, Index<…> is not directly implemented for arrays. This is partly because it would currently be impossible to provide blanket implementations for all array sizes, but mainly because it's not necessary; the implementation for slices is sufficient for most purposes.
The expression x[..] is translated to *std::ops::Index::index(&x, ..) by the compiler, which in turn is evaluated according to the usual method call semantics. Since there is no implementation of Index<RangeFull> for arrays, the compiler repeatedly dereferences &x and performs an unsized coercion at the end, eventually finding the implementation of Index<RangeFull> for [i32].
The process of calling a generic function, like f() in your example, is different from method call semantics. The compiler first infers what T is based on the argument you are passing; in this case T is inferred to be [i32; 4]. In the next step, the compiler verifies whether T satisfies the trait bounds, and since it doesn't, you get an error message.
If we want to make your code work, we need to make sure to pass a slice to f(). Since a slice is unsized, we need to pass it by reference, so we need to define f() like this:
fn f<T: ?Sized + Index<RangeFull>>(_: &T) {}
The ?Sized is necessary since type parameters receive an implicit Sized bound. When calling f(), we need to make sure T is actually inferred as [i32] rather than [i32; 4]. To this end, we can either explicitly specify T
f::<[_]>(&x);
or explicitly perform the unsized conversion before passing the argument, so the compiler infers the desired type:
f(&x as &[_]);
f(&x[..])

Resources