Access newtype in Rust - rust

I'm using a newtype, wrapping an array of integers:
struct Foo([int, ..5]);
Since, apparently, I cannot simply do this:
let foo = Foo([1,2,3,4,5]);
let bar = foo[2];
How exacty do I access the wrapped array?

There are one-and-a-half (soon to be two) ways:
#![feature(tuple_indexing)]
struct Foo([int, ..5]);
fn main() {
let foo = Foo([1,2,3,4,5]);
let Foo([_, foo_1, ..]) = foo;
let foo_3 = foo.0[3];
println!("[_, {}, _, {}, _]", foo_1, foo_3);
}
Specifically, tuple_indexing is likely to be un-gated soon, so you won't need the feature attribute to use it.
Basically, Foo is a tuple struct; that is, it behaves more or less just like a tuple that happens to have a name.

Related

the trait SliceIndex<[i32]> is not implemented for [RangeFrom<{integer}>; 1]

I have written a function which takes a generic parameter T with bound AsRef[i32].
Now I want to slice the input further inside my function with get method. But rust compiler would not let me use 1.. range to slice. I can use split_at method to split the slice. That will work. But my question is why can't I use array.as_ref().get([1..]) in this case? Do I need to add any other trait bounds to the generic type to make it work? If I do get with one index like array.as_ref().get(0) that works fine.
Here is my code -
fn find<T>(array: T, key: i32) -> Option<usize>
where
T: AsRef<[i32]>,
{
let arr = array.as_ref().get([1..]);
println!("slicing successful");
None
}
fn main() {
let arr = [1, 2, 3];
find(arr, 1);
}
Playground link.
You are confusing two syntax. The first one is the most commonly used to index a slice:
let arr = array.as_ref()[1..];
This is just syntax sugar for
let arr = array.as_ref().index(1..);
Note that for the second version to work, you need to have the std::ops::Index trait in scope.
This will not work as is because it returns a slice [i32], and [i32]: !Sized. Therefore you need to add a level of indirection:
let arr = &array.as_ref()[1..];
See the playground.
The second possible way is to use the get method of slices:
let arr = array.as_ref().get(1..);
See the playground.

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

How to destructure a Vec into variables that take ownership?

I have a struct
struct Foo {
foo1: String,
foo2: String,
foo3: String,
foo4: String,
// ...
}
I would like to create an instance of Foo from a vector.
let x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
match x.as_slice() {
&[ref a, ref b, ref c, ref d] => {
let foo = Foo {
foo1: a.to_string(),
foo2: b.to_string(),
foo3: c.to_string(),
foo4: d.to_string(),
};
},
_ => unreachable!(),
}
Do I have to copy the strings? Is there any better way to destructure the vector into a, b, c, d as well as transferring the ownership?
Actually, I don't mind x is completely destroyed after the destructuring. So I hope there is a pattern match for vectors apart from slices as well. For now it seems we can only destructure slices.
Do I have to copy the strings?
Not if you are willing to give up destructuring. I'm a big fan of itertools:
use itertools::Itertools; // 0.8.2
fn main() {
let x = vec![
"a".to_string(),
"b".to_string(),
"c".to_string(),
"d".to_string(),
];
if let Some((foo1, foo2, foo3, foo4)) = x.into_iter().tuples().next() {
let foo = Foo {
foo1,
foo2,
foo3,
foo4,
};
}
}
This transfers ownership of the vector (and thus the members) to an iterator, then the tuples adapter chunks up the values into a tuple. We take the first one of those and construct the value.
You could also use drain if you didn't want to give up ownership of the entire vector:
if let Some((foo1, foo2, foo3, foo4)) = x.drain(..4).tuples().next() {
Is there any better way to destructure the vector into a, b, c, d as well as transferring the ownership?
No, there is no mechanism to take ownership of a part of a Vec without creating another Vec (or another type that has the same limits) except for an iterator.
Destructuring slices isn't stable, and you can't move out of a slice because it's just a borrow — if you moved out, what would the Vec's destructor do?
Mutating the vector is the way to go here:
let mut x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
let foo = Foo {
foo4: x.pop().unwrap(),
foo3: x.pop().unwrap(),
foo2: x.pop().unwrap(),
foo1: x.pop().unwrap(),
};
println!("{:?}", foo);
playground
If you're willing to use nightly this is a one liner with #![feature(box_patterns)]:
#![feature(box_patterns)]
let x = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
let Ok(box [a, b, c, d]) = <Box<[String; 4]>>::try_from(x) else { unreachable!() };
Note on stability:
Do be aware that these box patterns will likely be replaced with a more general "deref" patterns in the future and thus most likely will never be stabilized as-is.
Whether those will allow movement of ownership is unknown, due to there not existing any kind of DerefInto trait, only Deref and DerefMut which borrow.
I expect, however, that the box_patterns feature won't be removed until there exists another way to do this. (Or at least, until another feature replaces it that can provide the same feature), so you can (mostly) safely use this feature and not be locked out in the future. In any case you can use one of the other answers to re-implement this should that happen.

How do I cope with lazy iterators?

I'm trying to sort an array with a map() over an iterator.
struct A {
b: Vec<B>,
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct B {
c: Vec<i32>,
}
fn main() {
let mut a = A { b: Vec::new() };
let b = B { c: vec![5, 2, 3] };
a.b.push(b);
a.b.iter_mut().map(|b| b.c.sort());
}
Gives the warning:
warning: unused `std::iter::Map` that must be used
--> src/main.rs:16:5
|
16 | a.b.iter_mut().map(|b| b.c.sort());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_must_use)] on by default
= note: iterators are lazy and do nothing unless consumed
Which is true, sort() isn't actually called here. This warning is described in the book, but I don't understand why this variation with iter_mut() works fine:
a.b.iter_mut().find(|b| b == b).map(|b| b.c.sort());
As the book you linked to says:
If you are trying to execute a closure on an iterator for its side effects, use for instead.
That way it works, and it's much clearer to anyone reading the code. You should use map when you want to transform a vector to a different one.
I don't understand why this variation with iter_mut() works fine:
a.b.iter_mut().find(|b| b == b).map(|b| b.c.sort());
It works because find is not lazy; it's an iterator consumer. It returns an Option not an Iterator. This might be why it is confusing you, because Option also has a map method, which is what you are using here.
As others have said, map is intended for transforming data, without modifying it and without any other side-effects. If you really want to use map, you can map over the collection and assign it back:
fn main() {
let mut a = A { b: Vec::new() };
let mut b = B { c: vec![5, 2, 3] };
a.b.push(b);
a.b =
a.b.into_iter()
.map(|mut b| {
b.c.sort();
b
})
.collect();
}
Note that vector's sort method returns (), so you have to explicitly return the sorted vector from the mapping function.
I use for_each.
According to the doc:
It is equivalent to using a for loop on the iterator, although break and continue are not possible from a closure. It's generally more idiomatic to use a for loop, but for_each may be more legible when processing items at the end of longer iterator chains. In some cases for_each may also be faster than a loop, because it will use internal iteration on adaptors like Chain.

Is there a way to shorten match expressions of non-Copy types using Option::and_then?

The Option::and_then function allows simplifying this code:
let foo = Some(1);
let bar = match foo {
Some(i) => Some(i + 1),
None => None,
};
println!("Foo: {:?}", foo);
into this:
let foo = Some(1);
let bar = foo.and_then(|i| Some(i + 1));
println!("Foo: {:?}", foo);
If I try the same thing with Strings, it doesn't compile:
let foo = Some("bla".to_string());
let bar = foo.and_then(|ref f| Some(f.clone()));
println!("Foo: {:?}", foo);
error[E0382]: use of moved value: `foo`
--> src/main.rs:4:27
|
3 | let bar = foo.and_then(|ref f| Some(f.clone()));
| --- value moved here
4 | println!("Foo: {:?}", foo);
| ^^^ value used here after move
|
= note: move occurs because `foo` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
However, the corresponding match expression works:
let foo = Some("bla".to_string());
let bar = match foo {
Some(ref f) => Some(f.clone()),
None => None,
};
println!("Foo: {:?}", foo);
Is there a way to shorten this match expression like my first example with integers?
Code on playground
In this minimal example, I could have used map, but in my real code I'm calling another function that returns an Option so I really need and_then. It's just that I didn't want to over-complicate the example with an extra function that didn't affect the problem.
I really need to use foo afterwards, otherwise there wouldn't be any problem (actually, foo is captured by a closure that I need to use more than once, and Man! did I have a hard time tracking down why the compiler kept refusing my code! The error the trait FnMut... is not implemented for the type [closure#...] doesn't give much indication into why it isn't).
I used clone in the example because I wanted a simple operation using the string. In the real code, foo is not a string (it's a Regex) and I'm not cloning it in the closure (I'm applying it on a string and processing the results). Moreover, this code will be called a large number of times so avoiding unnecessary allocations and copies is important.
Explanation
First of all: The method you actually want to use is map here, since you only want to change the inner value. and_then is useful if you create another Option in the closure.
To answer your question: It's correct that you can't access foo anymore. If you look at the function declaration...
fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U>
// ^^^^
... you see that the first argument is self. This means that the method consumes self (acquires the ownership) so foo is moved into the method and can't be used anymore.
Solution
If you only need bar afterwards (which is usually the case), you should just print bar. If you really need foo, too, you can do this:
let bar = foo.as_ref().map(|s| s.clone());
as_ref creates a new Option that only holds a reference to the original inner variable. References are Copy types, so that Option can be safely consumed by map.
You want to use Option::as_ref:
fn main() {
let foo = Some("bla".to_string());
let bar = foo.as_ref().and_then(|f| Some(f.clone()));
println!("Foo: {:?}", foo);
}
You could just clone foo, and call and_then on the result.
let bar = foo.clone().and_then (|f| Some (f));
Option implements Clone which works as you would expect.
let foo = Some("bla".to_string());
let bar = foo.clone();

Resources