How to specify const array in global scope in Rust? - arrays

When I tried to add a const array in the global scope using this code:
static NUMBERS: [i32] = [1, 2, 3, 4, 5];
I got the following error:
error: mismatched types:
expected `[i32]`,
found `[i32; 5]`
(expected slice,
found array of 5 elements) [E0308]
static NUMBERS2: [i32] = [1, 2, 3, 4, 5];
^~~~~~~~~~~~~~~
The only way I found to deal with this problem is to specify the length in the type:
static NUMBERS: [i32; 5] = [1, 2, 3, 4, 5];
Is there a better way? It should be possible to create an array without manually counting its elements.

Using [T; N] is the proper way to do it in most cases; that way there is no boxing of values at all. There is another way, though, which is also useful at times, though it is slightly less efficient (due to pointer indirection): &'static [T]. In your case:—
static NUMBERS: &'static [i32] = &[1, 2, 3, 4, 5];

You can use const for that, here is an example:
const NUMBERS: &'static [i32] = &[1, 2, 3, 4, 5];

Related

Parallel write to array with a unique indices array

This question is analogical to
Parallel write to array with an indices array
except that I guarantee the indices to be unique.
let indices = [1, 4, 7, 8];
let mut arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
indices.iter_par().for_each(|x| {
arr[x] = some_function(x);
});
Is there a way to achieve this in Rayon? Perhaps I should somehow use unsafe, because obviously borrow checker can't verify uniqueness of indices.
You can certainly do it with unsafe, for example by sending a pointer to the threads:
// thin wrapper over pointer to make it Send/Sync
#[derive(Copy, Clone)]
struct Pointer(*mut u32);
unsafe impl Send for Pointer {}
unsafe impl Sync for Pointer {}
let indices = [1, 4, 7, 8];
let mut arr = [1u32, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arr_ptr = Pointer(arr.as_mut_ptr());
indices.into_par_iter().for_each(move |x| {
// safety:
// * `indices` must be unique and point inside `arr`
// * `place` must not leak outside the closure
// * no element of `array` that is in `indices` may be accessed by
// some other thread while this is running
let place = unsafe { &mut *{arr_ptr}.0.add(x) };
*place = some_function(x);
});
But I'd reserve that kind of thing to use only as last resort. Once you introduce ad-hoc unsafe like this in your code base, you never know when you'll make a misstep and make your program vulnerable to random crashes and corruptions.

How do you merge two arrays of u8 and u16 elements into an array of u8 elements?

So I have an array I've just created of u8 (a) and a slice of u16 (b). How can I get an array that is the result of concatenating the elements of a with the elements of b after turning these into u8?
I've tried a lot of modifications of the following code, but there is always some error.
fn main() {
let a: [u8; 3] = [0x01, 0x02, 0x03];
let b: &[u16] = &[0x0405, 0x0607, 0x0809];
let result = [a,
b.iter().flat_map(|s| &s.to_be_bytes()).collect()]
.iter().flat_map(|e| e.iter()).collect();
assert_eq!(result, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
I understand the error in that piece of code but I don't know how to fix it without creating another.
Like, I can create a as a Vec<u8> so that collect() can collect into something that implements std::iter::FromIterator. But it collects into Vec<&u8>.
I also have the feeling that it should be way more simple than my example. As if I'm missing a specific function.
The following works:
fn main() {
let a: [u8; 3] = [0x01, 0x02, 0x03];
let b: &[u16] = &[0x0405, 0x0607, 0x0809];
let result: Vec<u8> = a.iter().copied()
.chain(
b.iter()
.flat_map(|s| std::array::IntoIter::new(s.to_be_bytes()))
)
.collect();
assert_eq!(result, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
This uses the newly added std::array::IntoIter, which converts an array [T; N] into an iterator of type T, as opposed to the .iter() which produces &T. This solves the issue of combining a u8 with a &u8.
Afterwards it uses .chain to attach both iterators together, which allows us to use different types of iterators that produce the same item, as opposed to using [a, b].iter(), which requires a and b to be the same type, as opposed to simply being iterators which produce the same type.
As a.iter().copied() and b.iter().flat_map(...) aren't the same type, you must use .chain instead of an array.

Why can a for loop in Rust iterate over a slice or iterator, but not an array?

Why can a for loop in Rust 1.44.0 iterate over a slice or iterator, but not an array? For example, the following threw me for a loop:
Loop over an array:
fn main() {
let a = [1, 2, 3, 4, 5];
for element in a {
println!("element={}", element);
}
}
error[E0277]: `[{integer}; 5]` is not an iterator
--> main.rs:4:20
|
4 | for element in a {
| ^ borrow the array with `&` or call `.iter()` on it to iterate over it
|
= help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 5]`
= note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]`
= note: required by `std::iter::IntoIterator::into_iter`
Loop over a slice (version 1):
fn main() {
let a = &[1, 2, 3, 4, 5];
for element in a {
println!("element={}", element);
}
}
element=1
element=2
element=3
element=4
element=5
Loop over a slice (version 2):
fn main() {
let a = [1, 2, 3, 4, 5];
for element in &a {
println!("element={}", element);
}
}
element=1
element=2
element=3
element=4
element=5
Loop over an array iterator:
fn main() {
let a = [1, 2, 3, 4, 5];
for element in a.iter() {
println!("element={}", element);
}
}
element=1
element=2
element=3
element=4
element=5
Rust can also loop in this way over a vector:
fn main() {
let v = vec![1, 2, 3, 4, 5];
for element in v {
println!("element={}", element);
}
}
element=1
element=2
element=3
element=4
element=5
The compiler tells you why: because arrays are not iterators.
There is a long standing issue to implement IntoIterator for arrays, unfortunately, adding this would be a breaking change and there are known issues in the ecosystem with “just doing it”, so progress is slow on this matter.
As of Rust 1.51, you can use array::IntoIter:
fn main() {
let a = [1, 2, 3, 4, 5];
for element in std::array::IntoIter::new(a) {
println!("element={}", element);
}
}
As of Rust 1.53, you can use IntoIterator, but as a special case, the compiler will continue to resolve array.into_iter() as (&array).into_iter() for backward compatibility. This includes the for-loop desugaring.
As of Edition 2021, the special case has been removed, and array iteration works as any other type.
Starting from Rust 1.53.0, the behavior of iteration for array has changed. Now we can iterate over arrays by value:
for i in [1, 2, 3] {
...
}
The code is legal now. See more at Announcing Rust 1.53.0.

How can I get Stream from 3 dimensional array in Java 8?

As I know to get Stream from 2 dimensional array but I want to know how I can get Stream from below 3 dimensional array?
int[][][] data = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
},
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
};
If you can do it with a two-dimensional array then doing it for N dimensional array is not that difficult.
The solution can be done as follows:
IntStream result = Arrays.stream(data)
.flatMap(Arrays::stream)
.flatMapToInt(Arrays::stream);
To better help understand what is going on above, you can split the method invocations as follows:
// the call to Arrays.stream yields a Stream<int[][]>
Stream<int[][]> result1 = Arrays.stream(data);
// the call to flatMap yields a Stream<int[]>
Stream<int[]> result2 = result1.flatMap(Arrays::stream);
// the call to flatMapToInt yields a IntStream
IntStream intStream = result2.flatMapToInt(Arrays::stream);
You just need to call flatMap another time to change the stream from int[][] to stream of int[].
IntStream stream = Arrays.stream(data)
.flatMap(twoDArray -> Arrays.stream(twoDArray))
.flatMapToInt(oneDArray -> Arrays.stream(oneDArray));

How do you copy between arrays of different sizes in Rust?

If I have two arrays of different sizes:
let mut array1 = [0; 8];
let array2 = [1, 2, 3, 4];
How would I copy array2 into the first 4 bytes of array1? I can take a mutable 4 byte slice of array1, but I'm not sure how or if I can assign into it.
Manually one can do
for (dst, src) in array1.iter_mut().zip(&array2) {
*dst = *src
}
for a typical slice. However, there is a likely faster specialization in clone_from_slice:
dst[..4].clone_from_slice(&src)
A slightly older method is to use std::io::Write, which was implemented for &mut [u8].
use std::io::Write;
let _ = dst.write(&src)
This will write up to the end of dst and return how many values were written in a Result. If you use write_all, this will return an Err if not all bytes could be written.
The most flexible way is to use iterators to handle each element successively:
for (place, data) in array1.iter_mut().zip(array2.iter()) {
*place = *data
}
.mut_iter creates an Iterator that yields &mut u8, that is, mutable references pointing into the slice/array. iter does the same but with shared references. .zip takes two iterators and steps over them in lock-step, yielding the elements from both as a tuple (and stops as soon as either one stops).
If you need/want to do anything 'fancy' with the data before writing to place this is the approach to use.
However, the plain copying functionality is also provided as single methods,
.copy_from, used like array1.copy_from(array2).
std::slice::bytes::copy_memory, although you will need to trim the two arrays because copy_memory requires they are the same length:
use std::cmp;
use std::slice::bytes;
let len = cmp::min(array1.len(), array2.len());
bytes::copy_memory(array1.mut_slice_to(len), array2.slice_to(len));
(If you know that array1 is always longer than array2 then bytes::copy_memory(array1.mut_slice_to(array2.len()), array2) should also work.)
At the moment, the bytes version optimises the best, down to a memcpy call, but hopefully rustc/LLVM improvements will eventually take them all to that.
You could simply use copy_from_slice() and use Range & Co:
fn main() {
let mut dest = [0; 8];
let src = [1, 2, 3, 4];
dest[..4].copy_from_slice(&src);
assert_eq!(dest, [1, 2, 3, 4, 0, 0, 0, 0]);
}
Inverse case:
fn main() {
let src = [1, 2, 3, 4, 5, 6, 7, 8];
let mut dest = [0; 4];
dest.copy_from_slice(&src[2..6]);
assert_eq!(dest, [3, 4 ,5, 6]);
}
Combined case:
fn main() {
let src = [1, 2, 3, 4, 5, 6, 7, 8];
let mut dest = [0; 4];
dest[1..3].copy_from_slice(&src[3..5]);
assert_eq!(dest, [0, 4, 5, 0]);
}

Resources