Related
Let's say I have:
let it = [1, 2, 3].into_iter();
let jt = [4, 5, 6].into_iter();
let kt = [7, 8, 9].into_iter();
Then I have boolean conditions i, j and k. I want to generate an iterator that conditionally chains it, jt and kt together based on the values of i, j and k. Can I do this with just the built-in Rust Iterator functionality?
You can make Option into an iterator.
let it = i.then_some([1, 2, 3]).into_iter().flatten();
let jt = j.then_some([4, 5, 6]).into_iter().flatten();
let kt = k.then_some([7, 8, 9]).into_iter().flatten();
let iter = it.chain(jt).chain(kt);
If the condition is false, then condition.then_some(...) will return None, making an empty iterator. Otherwise a Some(...) is returned. into_iter().flatten() will transform Option<impl IntoIterator<Item=T>> to impl Iterator<Item=T>.
You're going to run into a slight issue if you want to use bare iterators:
If you write the following:
let iter = [1, 2, 3].into_iter();
let iter = if some_condition {
iter.chain([4, 5, 6])
} else {
iter
}
You'll get an error which boils down to this:
= note: expected struct `std::iter::Chain<std::array::IntoIter<_, _>, std::array::IntoIter<{integer}, 3>>`
found struct `std::array::IntoIter<_, _>`
iter has type IntoIter, but iter.chain() has type Chain<IntoIter, ...>
To get around this, you have a few options:
you can use a trait object, which behaves a bit like an interface from languages like Java, but loses some performance:
let iter = [1, 2, 3].into_iter();
let mut iter: Box<dyn Iterator<Item = i32>> = Box::new(iter);
if some_condition {
iter = Box::new(iter.chain([4, 5, 6]));
}
or, probably a better solution, if you can sacrifice laziness, is to just use a Vec:
// save heap allocations by pre-allocating the whole vec
let len = if some_condition { 6 } else { 3 };
let mut items = Vec::with_capacity(len);
items.extend([1, 2, 3]);
if some_condition {
items.extend([4, 5, 6]);
}
This is a good use for the either crate. Either implements Iterator when both the left and right sides also implement Iterator, so it can be easily used to chain iterators together.
Given any three iterators it, jt, and kt that iterate over the same Item, with accompanying booleans i, j, and k, you can write a function that chains them together like this:
use either::Either;
use std::iter;
fn chain<'a, I, J, K, Item>(
it: I,
jt: J,
kt: K,
i: bool,
j: bool,
k: bool,
) -> iter::Chain<
iter::Chain<Either<I, iter::Empty<Item>>, Either<J, iter::Empty<Item>>>,
Either<K, iter::Empty<Item>>,
>
where
I: Iterator<Item = Item>,
J: Iterator<Item = Item>,
K: Iterator<Item = Item>,
{
let iter = if i {
Either::Left(it)
} else {
Either::Right(iter::empty())
};
let iter = iter.chain(if j {
Either::Left(jt)
} else {
Either::Right(iter::empty())
});
let iter = iter.chain(if k {
Either::Left(kt)
} else {
Either::Right(iter::empty())
});
iter
}
Calling this function will result in an iterator conditional on the input. For example, calling
let it = [1, 2, 3].into_iter();
let jt = [4, 5, 6].into_iter();
let kt = [7, 8, 9].into_iter();
chain(it, jt, kt, true, false, true).collect::<Vec<_>>();
gives
[1, 2, 3, 7, 8, 9]
as expected.
You can try it using this playground.
We have a function with two vectors. We would like to ensure that the length of the two vectors is the same. Is there a way to enforce that from the type level in Rust?
For example, here we guarantee that the two input vectors num1 and num2 are of length 4.
fn foo(nums1: [i32; 4], nums2: Vec<[i32; 4]>) {
println!("{:?}", nums1);
println!("{:?}", nums2);
}
What we really want is this:
fn bar(nums1: Vec<i32>, nums2: Vec<Vec<i32>>) {
for row in &nums2 {
assert!(nums1.len() == row.len());
}
println!("{:?}", nums1);
println!("{:?}", nums2);
}
We want them to be of the same length but they can be of any length. The above works fine of cause, however, it is a runtime check instead of a compile time check.
Is there a way to achieve this in compile time with some Rust generic, macro, or whatever dark magic?
# N to be any integer larger than 1
fn baz(nums1: [i32; N], nums2: Vec<[i32; N]>) {
println!("{:?}", nums1);
println!("{:?}", nums2);
}
You can use const generics.
fn foo<const N: usize>(nums1: [i32; N], nums2: Vec<[i32; N]>) {
println!("{:?}", nums1);
println!("{:?}", nums2);
}
fn main() {
foo([1, 2], vec![[1, 2], [1, 2]]);
foo([1, 2, 3], vec![[1, 2], [1, 2]]);
// ^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
}
I have read How to iterate a Vec<T> with the indexed position? where the answer is to use enumerate in a for-loop.
But if I don't use a for-loop like this:
fn main() {
let v = vec![1; 10]
.iter()
.map(|&x| x + 1 /* + index */ ) // <--
.collect::<Vec<_>>();
print!("v{:?}", v);
}
How could I get the index in the above closure?
You can also use enumerate!
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, &x)| x + i)
.collect::<Vec<_>>();
println!("v{:?}", v); // prints v[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Let's see how this works. Iterator::enumerate returns Enumerate<Self>. That type also implements Iterator:
impl<I> Iterator for Enumerate<I>
where
I: Iterator,
{
type Item = (usize, <I as Iterator>::Item);
// ...
}
As you can see, the new iterator yields tuples of the index and the original
value.
You can simply use enumerate:
fn main() {
let v = vec![1; 10]
.iter()
.enumerate()
.map(|(i, x)| i + x)
.collect::<Vec<_>>();
print!("v{:?}", v);
}
The reason for this is because the for loop takes an enumerator:
In slightly more abstract terms:
for var in expression {
code
}
The expression is an iterator.
I'm writing some code in Rust (mainly as a POC). The code takes a 2D array, passes it to a second function to do some matrix math (I know there is a standard library to do this, but I want to get used to how things work).
The problem is that the assignment to a 2D array is causing an issue.
My code looks like this
fn main()
{
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(&array_one, &array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1:&[&[i32;4];4], vec2:&[&[i32;4];4]) -> [[i32; 4];4]
{
// we need to deference the parameters passed in
let vec_one:[[i32;4];4] = vec1;
let vec_two:[[i32;4];4] = vec2;
// we need to store the sum
let mut sum = 0;
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4
{
for vtwo in 0..4
{
for k in 0..4
{
sum = sum + vec1[[vone].k] * vec2[[k].vtwo];
}
result[[vec_one].vec_two] = sum;
sum = 0;
}
}
return result;
}
I've also tried result[vec_one][vec_two] = sum but when I come to compile, it looks like there is a problem assigning to array.
What am I doing wrong here?
Here is your error, I believe (at least one of them):
<anon>:15:34: 15:44 error: mismatched types:
expected `&[&[i32; 4]; 4]`,
found `&[[i32; 4]; 4]`
(expected &-ptr,
found array of 4 elements) [E0308]
<anon>:15 let result = matrix_multiply(&array_one, &array_two);
^~~~~~~~~~
The problem is, reference or dereference of arrays can't go on multiple levels of their nesting. This is because the memory layout of, say, [&[i32; 4]; 4] and [[i32; 4]; 4] is radically different, both in contents and in size - the former array consists of four pointers to other arrays (4*4=16/8*4=32 bytes total, depending on architecture of your machine), while the latter consists of four arrays laid out sequentially (4*4*4=64 bytes total). There is simply no way to go from [[i32; 4]; 4] to &[&[i32; 4]; 4] without rebuilding the outer array, which Rust won't ever do for you because it is too much magic.
You don't really need to use the inner reference; in fact, you probably don't even need to pass these arrays by reference at all: arrays of Copy types are Copy as well, so you can pass them by value. They are small enough to not cause any performance impact, and the compiler will probably optimize it automatically anyway:
fn main() {
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(array_one, array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1: [[i32; 4]; 4], vec2: [[i32; 4]; 4]) -> [[i32; 4]; 4] {
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4 {
for vtwo in 0..4 {
let mut sum = 0;
for k in 0..4 {
sum += vec1[vone][k] * vec2[k][vtwo];
}
result[vone][vtwo] = sum;
}
}
result
}
(try it here)
I've also made your code more idiomatic according to the current community practices (braces positioning, spacing, etc.), and I've fixed the weird syntax for accessing arrays.
If you write
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
the type of array_one will be [[i32;4];4] because the line arrays are copied into array_one. Borrowing this via &array_one gives you something of type &[[i32;4];4] which is very different from &[&[T; 4]; 4] (what the function you try to call expects).
Option1 -- Create [&[T; 4]; 4]:
let array_one = [&line1, &line3, &line4, &line2];
some_function(&array_one);
...
fn some_function(matrix: &[&[i32;4];4]) {...}
Option2 -- Change the function sitnature:
let array_one = [line1, line3, line4, line2];
some_function(&array_one);
...
fn some_function(matrix: &[[i32;4];4]) {...}
If you're interested in dealing with multi-dimensional arrays of arbitrary sizes, perhaps you'll find my experimental multiarray crate useful. It basically tries to offer types similar to Box<[T]>, &[T] and &mut[T] for two or more dimensions. Here's an untested example just to get an idea of what I was trying to do:
extern crate multiarray;
use multiarray::*;
fn main() {
// the backing memory will be a dynamically allocated
// linear array with 4 elements in row-major (C-style) order.
let mut matrix = Array2D::new([2, 2], 0i32);
matrix[[0,0]] = 1; matrix[[0,1]] = 2;
matrix[[1,0]] = 3; matrix[[1,1]] = 4;
let mut square = Array2D::new([2, 2], 0i32);
// the borrow methods create reference-like proxies
mat_product(matrix.borrow(), matrix.borrow(),
square.borrow_mut());
}
fn mat_product(a: Array2DRef<i32>, b: Array2DRef<i32>,
mut c: Array2DRefMut<i32>) {
let rows = a.extents()[0]; // extent of 1st dimension
let intr = a.extents()[1]; // extent of 2nd dimension
let cols = b.extents()[1]; // extent of 2nd dimension
assert!(intr == b.extents()[0]);
assert!(rows == c.extents()[0]);
assert!(cols == c.extents()[1]);
for i in 0..rows {
// the i-th row of a and c...
let a_row_i = a.eliminated_dim(0, i);
let mut c_row_i = c.reborrow_mut().eliminated_dim(0, i);
for j in 0..cols {
c_row_i[j] = dot_product(a_row_i, b.eliminated_dim(1, j));
// ^^^j-th column of b^^^
}
}
}
fn dot_product(a: Array1DRef<i32>, b: Array1DRef<i32>) -> i32 {
a.zip(b).fold(0, |acc,(&x,&y)| acc + x * y)
}
Editor's note: The code in this question predates Rust 1.0. Since then, semantics have changed and some of the assertions made in the question are no longer true.
I have the following piece of code:
extern crate debug;
use std::mem::size_of_val;
struct A<'a> {
a: &'a [i64],
}
fn main() {
// code
}
When I define a slice with & (i.e. &[1, 2, 3]) as in the following println!
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
the output is
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
Defining a slice without &
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
gives me the same result
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
If I first try to bind an instance of a struct A, whose a field is initialized with a reference to a slice (i.e. using &), to a variable x
let x = A { a: &[1, 2, 3] }; // &[1, 2, 3] is a reference to a slice
and I try to execute a similar println! as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get
16 - A<'static>{a: &[1i64, 2i64, 3i64]}
However, if I bind an instance of A, whose a field is initialized to a slice (not a reference to a slice using &), to a variable x
let x = A { a: [1, 2, 3] };
and I try to execute a similar println! as the previous ones
println!("{} - {:?}", size_of_val(&x), x);
I get the following build error:
/prpath/main.rs:12:20: 12:29 error: borrowed value does not live long enough
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
^~~~~~~~~
/prpath/main.rs:11:11: 15:2 note: reference must be valid for the block at 11:10...
/prpath/main.rs:11 fn main() {
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
/prpath/main.rs:13
/prpath/main.rs:14 println!("{} - `{:?}`", size_of_val(&x), x);
/prpath/main.rs:15 }
/prpath/main.rs:12:5: 12:31 note: ...but borrowed value is only valid for the statement at 12:4; consider using a `let` binding to increase its lifetime
/prpath/main.rs:12 let x = A { a: [1 ,2, 3] };
^~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
I was expecting that only the A { a: &[1, 2, 3] } definition was allowed because A.a should have &[i64] type, but, apparently, Rust allows us to not include an & symbol.
What is the difference between A { a: &[1, 2, 3] } and A { a: [1, 2, 3] }? Why are we allowed to use A { a: [1, 2, 3] } (in the second example above)?
First, you can use a [T,..n] where a &[T] is expected, the conversion to a slice is implicit. So following code is perfectly valid:
let a = [1u, 2, 3];
let b: &[uint] = a;
Your situation is a purely lifetime problem. Your struct is
struct A<'a> {
a: &'a [i64],
}
It holds a slice. A slice is nothing more than a reference to the first element and a count of the number of elements. That's why size_of_val() called on a A will always return 16: it's the size of a slice, one u64 for the pointer, and one u64 for the number of elements (as you seems to be on a 64bits computer).
So in your code, the struct does not own the array. The difference in behavior you observe is due to the difference about when the array does out of scope.
First case:
let x = A { a: [1, 2, 3] };
Here you define an array, and stores a slice to this array in your struct. Then when reaching the ;, your array does out of scope and is destroyed, and thus the reference in x is not valid anymore: it is forbidden by the compiler.
Second case:
let x = A { a: &[1, 2, 3] };
It is more peculiar. Your array is stored in an anonymous variable. In fact, writing
let foo = &42u;
is equivalent to writing
let _anonymousvariable = 42u;
let foo = &_anonymousvariable;
Except that you can't reach _anonymousvariable directly.
It's exactly the same for you, your code is equivalent to
let _anonymous_array = [1, 2, 3]
let x = A { a: &_anonymous_array };
and thus is perfectly valid.
Last case:
When you write everything directly in the println!(). Thanks to previous case, we now see why this works:
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
but in this case there is no problem either:
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
because your arrays only go out of scope when reaching the ;, and no reference to them exist past this point, so they can be safely deleted and the compiler is happy.