How to initialize an array with an iterator in Rust? [duplicate] - arrays

I'm having trouble initializing a fixed length array. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:
#[derive(Debug)]
struct Foo { a: u32, b: u32 }
impl Default for Foo {
fn default() -> Foo { Foo{a:1, b:2} }
}
pub fn main() {
let mut foo_array: [Foo; 10];
// Do something here to in-place initialize foo_array?
for f in foo_array.iter() {
println!("{:?}", f);
}
}
error[E0381]: use of possibly uninitialized variable: `foo_array`
--> src/main.rs:13:14
|
13 | for f in foo_array.iter() {
| ^^^^^^^^^ use of possibly uninitialized `foo_array`
I implemented the Default trait, but Rust does not seem to call this by default akin to a C++ constructor.
What is the proper way to initialize a fixed length array? I'd like to do an efficient in-place initialization rather than some sort of copy.
Related: Why is the Copy trait needed for default (struct valued) array initialization?
Related: Is there a way to not have to initialize arrays twice?

The safe but somewhat inefficient solution:
#[derive(Copy, Clone, Debug)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Since you're specifically asking for a solution without copies:
use std::mem::MaybeUninit;
#[derive(Debug)]
struct Foo {
a: u32,
b: u32,
}
// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
fn drop(&mut self) {
println!("Destructor running for a Foo");
}
}
pub fn main() {
let array = {
// Create an array of uninitialized values.
let mut array: [MaybeUninit<Foo>; 10] = unsafe { MaybeUninit::uninit().assume_init() };
for (i, element) in array.iter_mut().enumerate() {
let foo = Foo { a: i as u32, b: 0 };
*element = MaybeUninit::new(foo);
}
unsafe { std::mem::transmute::<_, [Foo; 10]>(array) }
};
for element in array.iter() {
println!("{:?}", element);
}
}
This is recommended by the documentation of MaybeUninit.

You can use the arrayvec crate:
Cargo.toml
[package]
name = "initialize_array"
version = "0.1.0"
edition = "2018"
[dependencies]
arrayvec = "0.7.2"
src/main.rs
use arrayvec::ArrayVec;
use std::iter;
#[derive(Clone)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
.take(10)
.collect::<ArrayVec<_, 10>>()
.into_inner()
.unwrap_or_else(|_| unreachable!());
}

The easiest way is to derive Copy on your type and initialize the array with that, copying the element N times:
#[derive(Copy)]
struct Foo {
a: u32,
b: u32,
}
let mut foo_array = [Foo { a: 1, b: 2 }; 10];
If you want to avoid copying, there are a couple options. You can use the Default trait:
let mut foo_array: [Foo; 10] = Default::default();
However, this is limited to arrays up to 32 elements. With const generics, it is now possible for the standard library to provide Default for all arrays. However, this would be a backward incompatible change for subtle reasons that are being worked on.
For now, you can take advantage of the fact that const values are also allowed in array repetition expressions:
const FOO: Foo = Foo { a: 1, b: 2 };
let mut foo_array = [FOO; 10];
If you're on nightly, you can use array::map:
#![feature(array_map)]
let mut foo_array = [(); 10].map(|_| Foo::default())

Related

Best Way To Mutate Arrays in Structs?

I have a struct like the following
struct Foo {
x: [i8;64]
y: i8
}
And I want to update a value inside array x in Foo when I pass it through a function. The best solution I can come up with is make a mutable copy of x and then update that copy, and then create a new Foo with the new array.
fn updateFoo(myFoo: Foo, index: usize, newvalue: i8) -> Foo {
let mut newX = myFoo.x;
newX[index] = newvalue;
Foo {
x: newX,
y: myFoo.y,
}
}
Is this an efficient and idiomatic way of mutating arrays within a struct in Rust? What alternatives are there for me to update values inside of an array inside Rust? Thank you for your help.
You can also just pass in a mutable ref to Foo:
struct Foo {
x: [i8; 64],
y: i8,
}
fn updateFoo(myFoo: &mut Foo, index: usize, newvalue: i8) {
myFoo.x[index] = newvalue;
}
playground

Cannot borrow as mutable more than once at a time in asynchronous code with a loop

What is causing multiple simultaneous mutable borrows in this code? I suspect it has to do with the <'a> declared on the type F because if I remove the 'a from the struct I am able to write the loop just fine.
This works, but this does not:
struct F<'a> {
i: u32,
a: &'a mut u32,
}
impl<'a> F<'a> {
async fn looper(self, x: &'a mut u32) -> F<'a> {
let mut this = Some(self);
loop {
let me = this.take().unwrap();
let new_me = me.inner(x).await;
this.replace(new_me);
}
}
async fn inner(self, x: &'a mut u32) -> F<'a> {
*x += self.i;
self
}
}
playground
error[E0499]: cannot borrow `*x` as mutable more than once at a time
--> src/lib.rs:12:35
|
12 | let new_me = me.inner(x).await;
| ^ mutable borrow starts here in previous iteration of loop

How do I determine the size of an array at compile time in Rust?

I have a C library that expects string type that explicitly defines the string length:
#[repr(C)]
pub struct FFIStr {
len: usize,
data: *const u8,
}
Because this type is used as a static, I'd like a way to safely declare it using a const function or macro (instead of manually setting len).
My first attempt was to use a macro and len(), however in versions before 1.39.0, it is not possible to get the length of a slice as a const fn:
macro_rules! ffi_string {
($x:expr) => {
FFIStr { len: $x.len(), data: $x as *const u8 }
};
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string!(b"Hello, world!");
error: core::slice::<impl [T]>::len` is not yet stable as a const function
My second attempt was to use std::mem::size_of<T>, but there doesn't appear to be a way to get the type of the static array short of using generics:
const fn ffi_string<T>(s: &'static T) -> FFIStr {
FFIStr { len: ::std::mem::size_of::<T>(), data: s as *const _ as *const _ }
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string(b"Hello, world!");
While this works (surprisingly), it's horribly prone to misuse as it wildly casts whatever you pass it to a *const u8.
It seems like const_generics would be a nice solution to this, but they're currently unstable:
const fn ffi_string<const SIZE: usize>(s: &'static [u8; SIZE]) -> FFIStr {
FFIStr { len: SIZE, data: s as *const u8 }
}
#[no_mangle]
pub static mut X: FFIStr = ffi_string(b"Hello, world!");
error[E0658]: const generics are unstable
Is there a better way of determining the size of a static array at compile time?
In Rust 1.39.0 [T]::len was stabilised as a const function, now making this straight forward:
const ARRAY: [i32; 3] = [1, 2, 3];
const ARRAY_SIZE: usize = ARRAY.len();
fn main() {
assert_eq!(3, ARRAY_SIZE);
}
In earlier versions of Rust, here's one way based on the common C ARRAY_SIZE macro:
macro_rules! array_size {
($x:expr) => (
(size_of_val($x) / size_of_val(&$x[0]))
)
}
const fn size_of_val<T>(_: &T) -> usize {
std::mem::size_of::<T>()
}
fn main() {
assert_eq!(3, array_size!(&[1, 2, 3]));
assert_eq!(13, array_size!(b"Hello, world!"));
}
It uses a const generic function size_of_val<T> to determine the type and thus the size of a value passed by reference (the built-in std::mem::size_of_val isn't const).
Note: This doesn't work for arrays of size 0. This can be fixed by using size_of_val($x) / size_of_val(unsafe { &*$x.as_ptr() }) at the cost of wrongly accepting non-array types (e.g. &String).

How to extract a usize bytes and return them? [duplicate]

I want to create array like this:
let arr = [0; length];
Where length is a usize. But I get this error
E0307
The length of an array is part of its type. For this reason, this length
must be a compile-time constant.
Is it possible to create array with dynamic length? I want an array, not a Vec.
Is it possible to create array with dynamic length?
No. By definition, arrays have a length defined at compile time. A variable (because it can vary) is not known at compile time. The compiler would not know how much space to allocate on the stack to provide storage for the array.
You will need to use a Vec:
let arr = vec![0; length];
See also:
Is it possible to control the size of an array using the type parameter of a generic?
This should be possible after variable length arrays (VLA) are implemented.
You can create your own HeapArray. It's not that complicated if you read alloc's docs:
use std::alloc::{alloc, dealloc, Layout};
pub struct HeapArray<T> {
ptr: *mut T,
len: usize,
}
impl<T> HeapArray<T> {
pub fn new(len: usize) -> Self {
let ptr = unsafe {
let layout = Layout::from_size_align_unchecked(len, std::mem::size_of::<T>());
alloc(layout) as *mut T
};
Self { ptr, len }
}
pub fn get(&self, idx: usize) -> Option<&T> {
if idx < self.len {
unsafe { Some(&*(self.ptr.add(idx))) }
} else {
None
}
}
pub fn get_mut(&self, idx: usize) -> Option<&mut T> {
if idx < self.len {
unsafe { Some(&mut *(self.ptr.add(idx))) }
} else {
None
}
}
pub fn len(&self) -> usize {
self.len
}
}
impl<T> Drop for HeapArray<T> {
fn drop(&mut self) {
unsafe {
dealloc(
self.ptr as *mut u8,
Layout::from_size_align_unchecked(self.len, std::mem::size_of::<T>()),
)
};
}
}
impl<T> std::ops::Index<usize> for HeapArray<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get(index).unwrap()
}
}
impl<T> std::ops::IndexMut<usize> for HeapArray<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_mut(index).unwrap()
}
}
You may also add methods like as_slice, get_unchecked, etc.

How can I initialize an array using a function? [duplicate]

This question already has answers here:
Initialize a large, fixed-size array with non-Copy types
(8 answers)
Closed last month.
I want to create an array of 10 empty vectors in Rust, but [Vec::new(); 10] doesn't work as Vec doesn't implement Copy. How can I do this, and in more general terms how can I initialize a array by repeatedly calling a function?
As of Rust 1.55.0, Sep 2021
You can use array's .map() method for general functions:
let arr: [Vec<u32>; 10] = [(); 10].map(|_| Vec::with_capacity(100));
(With Rust 1.63.0, Aug 2022 consider using from_fn).
As of Rust 1.63
Use from_fn:
let array: [usize; 5] = core::array::from_fn(|i| i * 2);
assert_eq!(array, [0, 2, 4, 8, 10]);
For your specific case, you can just use Default:
let v: [Vec<String>; 10] = Default::default();
For the general case, you can create an iterator out of your function and then collect into the array using ArrayVec:
use arrayvec::ArrayVec; // 0.4.10
use std::iter;
fn make<R>(f: impl FnMut() -> R) -> [R; 10] {
let a: ArrayVec<_> = iter::repeat_with(f).collect();
a.into_inner()
.unwrap_or_else(|_| panic!("Did not have enough elements"))
}
fn main() {
let mut a = 0;
let arr = make(|| {
a += 3;
a
});
println!("{:?}", arr);
// [3, 6, 9, 12, 15, 18, 21, 24, 27, 30]
}
See also:
How do I collect into an array?
I see two possible approaches
First
A simple solution using macro
macro_rules! array {
($v: expr; 1) => ([$v]);
($v: expr; 2) => ([$v, $v]);
($v: expr; 3) => ([$v, $v, $v]);
($v: expr; 4) => ([$v, $v, $v, $v]);
($v: expr; 5) => ([$v, $v, $v, $v, $v]);
// until 32
}
let a = array![Vec::new(); 3];
It's a bit verbose, but even the standard library uses this kind of construct.
Second
After realizing a connection between this question and another that I had answered before, I wrote this solution using nodrop
extern crate nodrop;
macro_rules! array {
($e: expr; $n:expr) => (
{
use std::mem;
use std::ptr;
use nodrop::NoDrop;
struct ArrayBuilder<T> {
len: usize,
data: *mut T,
}
impl<T> Drop for ArrayBuilder<T> {
fn drop(&mut self) {
unsafe {
while self.len > 0 {
let offset = (self.len as isize) - 1;
self.len -= 1;
ptr::drop_in_place(self.data.offset(offset));
}
}
}
}
let mut v: NoDrop<[_; $n]> = NoDrop::new(unsafe {
mem::uninitialized()
});
// helps type inference for v
if false { v[0] = $e; }
let mut builder = ArrayBuilder {
len: 0,
data: (&mut *v as *mut _) as *mut _
};
unsafe {
for i in 0..$n {
ptr::write(builder.data.offset(i as isize), $e);
builder.len = i + 1;
}
}
builder.len = 0;
v.into_inner()
}
)
}
let a = array![Vec::new(); 3];
And a test that indicates that it does not leak memory
#[test]
fn test() {
static mut COUNT: usize = 0;
#[derive(Debug)]
struct X(usize);
impl Drop for X {
fn drop(&mut self) {
println!("drop {:?}", self.0);
}
}
impl X {
fn new() -> X {
unsafe {
if COUNT == 3 {
panic!();
}
let x = X(COUNT);
COUNT += 1;
x
}
}
}
array![X::new(); 6];
}
In this test, the method X::new panics when creating X(3), so X(0), X(1), X(2) must be dropped.
Others
There is an unsafe solution here.
Edit: Outdated (applies to a Rust version lower than 1.55.0):
There is a crate called arr_macro that does exactly what you want:
fn main() {
let array: [Vec<String>; 10] = arr![Vec::new(); 10];
println!("{:?}", array) // [[], [], [], [], [], [], [], [], [], []]
}

Resources