1

Here is my code. Original problem has much bigger code, but in the end I squeeze it into next one:

struct Data<'a> {
    f: [&'a mut [u8]; 2],
}

impl Data<'_> {
    fn new() -> Self {
        let p = Self {
            f: [&mut [1u8, 2u8], &mut [3u8, 4u8, 5u8]],
        };
        p.f[0][1] = 5;
        p.f[1][2] = 7;
        p
    }
}

fn main() {
    let v: Data = Data::new();
    println!("{:?}", v.f);
}

I cannot figure out how to keep "p" variable alive! It died too early. Also I cannot put life parameter inside array (before mut), expressions does not except life parameters. I cannot put life parameter in Self, it causes error.

1
  • 1
    Can you elaborate on the actual problem. Why wouldn't f: [Vec<u8>; 2] be the solution for instance? Commented Apr 15, 2024 at 22:16

1 Answer 1

2

The error message you get from the compiler explains what the problem is:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:8:22
   |
6  |     fn new() -> Self {
   |                 ---- return type is Data<'1>
7  |         let p = Self {
8  |             f: [&mut [1u8, 2u8], &mut [3u8, 4u8, 5u8]],
   |                ------^^^^^^^^^^-----------------------
   |                |     |
   |                |     creates a temporary value which is freed while still in use
   |                this usage requires that borrow lasts for `'1`
...
13 |     }
   |     - temporary value is freed at the end of this statement

The arrays, such as [1u8, 2u8] are owned data. Creating such arrays and returning them would be fine. However, (mutable) references to these arrays, i.e. slices, are not something you can return from the function. This is because the owner of the array is a temporary variable in the new function, which is not accessible outside of that function.

Assuming you want to return a struct containing two arrays of integers, each of "any" length, you should use either a vector (which also allows resizing):

struct Data {
    f: [Vec<u8>; 2],
}

impl Data {
    fn new() -> Self {
        let mut p = Self {
            f: [vec![1u8, 2u8], vec![3u8, 4u8, 5u8]],
        };
        p.f[0][1] = 5;
        p.f[1][2] = 7;
        p
    }
}

Or a box:

struct Data {
    f: [Box<[u8]>; 2],
}

impl Data {
    fn new() -> Self {
        let mut p = Self {
            f: [Box::new([1u8, 2u8]), Box::new([3u8, 4u8, 5u8])],
        };
        p.f[0][1] = 5;
        p.f[1][2] = 7;
        p
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

You are totally right, I also thought of these two possibilities. The idea behind original code is trial to imitate c double array (ushort** a), which is array of references on other two ushort arrays. On machine level this approach allows to avoid dynamic allocations and reach fast speed. In Rust I already used Vec approach, which work quite slower than C version but impressive faster than C++. Box approaches I did not try, because it will allocate memory (as I understood), so I don't expect it will be faster than Vec. I hope there should be some workaround in Rust.
After double check I found that in C code there was also malloc for arrays, so I think Box option is most closed to original idea and hopefully fast enough. Thank you very much.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.