How to solve borrowed lifetime error in my code block?

Block_2 does not work.
How to start block_2 instead of block_1?
play

const N: u8 = 3;

pub struct InterVal<'a> {
    // ...
    pub name: [&'a str; N as usize],
    // ...
}

fn main() {

   println!("N = {:?}\n", N);
   
   let mut val_i: InterVal = InterVal {
       name: [""; N as usize], 
   };   
   
   println!("val_i.name = {:?}", &val_i.name);
   
   let mut i: usize = 0;
      // let t01 = "name_".to_string() + &(i+1).to_string();
      // let t02 = t01.as_str();
   loop {
      if i == N as usize {break;}
        
      // Block_1:
      val_i.name[i] = "name_";

      // Block_2:
      // let t02 = "name_".to_string() + &(i+1).to_string();
      // val_i.name[i] = &t02;

    i = i + 1;
   }    
   
   println!("val_i.name = {:?}", &val_i.name);
}

The value you create here gets dropped at the end of the current iteration of the loop. Therefore you can't keep references to it for longer than that, they'd be dangling. Just store owned Strings in your InterVal instead:

const N: u8 = 3;

pub struct InterVal {
    // ...
    pub name: [String; N as usize],
    // ...
}

fn main() {
    println!("N = {:?}\n", N);

    let mut val_i: InterVal = InterVal {
        name: core::array::from_fn(|_| "".to_owned()),
    };

    println!("val_i.name = {:?}", &val_i.name);

    let mut i: usize = 0;
    // let t01 = "name_".to_string() + &(i+1).to_string();
    // let t02 = t01.as_str();
    loop {
        if i == N as usize {
            break;
        }

        // Block_1:
        //val_i.name[i] = "name_";

        // Block_2:
        val_i.name[i] = format!("name_{}", i + 1);

        i = i + 1;
    }

    println!("val_i.name = {:?}", &val_i.name);
}

Playground.

Then you could further simplify your example to just array::from_fn:

const N: u8 = 3;

pub struct InterVal {
    // ...
    pub name: [String; N as usize],
    // ...
}

fn main() {
    println!("N = {:?}\n", N);

    let val_i: InterVal = InterVal {
        name: core::array::from_fn(|i| format!("name_{}", i + 1)),
    };

    println!("val_i.name = {:?}", &val_i.name);
}

Playground.

2 Likes

Thank you.
This is a test example.
Wanted to get away from using a heap
for the fastest processing of short strings.

All data, including structures, are on the stack.
ок.

In your example you are creating a heap allocated string. You just stored a reference to the heap allocation, instead of taking the String instance by ownership. You could use something like arrayvec::ArrayString to create stack-allocated strings instead. I'd try to measure the performance of String vs ArrayString for real-life workloads of your program, just to be sure whether stack-allocated strings are a worthwhile optimization.

1 Like

I looked at arrayvec::ArrayString
but couldn't adapt it to my code block.
Could you please provide that part?
Thanks.

Sure, I was thinking you'd just replace String with ArrayString:

use arrayvec::ArrayString;

const N: u8 = 3;

pub struct InterVal {
    // ...
    pub name: [ArrayString<100>; N as usize],
    // ...
}

fn main() {
    println!("N = {:?}\n", N);

    let mut val_i: InterVal = InterVal {
        name: core::array::from_fn(|_| ArrayString::new()),
    };

    println!("val_i.name = {:?}", &val_i.name);

    let mut i: usize = 0;
    // let t01 = "name_".to_string() + &(i+1).to_string();
    // let t02 = t01.as_str();
    loop {
        if i == N as usize {
            break;
        }

        // Block_1:
        //val_i.name[i] = "name_";

        // Block_2:
        val_i.name[i].push_str(&format!("name_{}", i + 1));

        i = i + 1;
    }

    println!("val_i.name = {:?}", &val_i.name);
}

Playground.

2 Likes

I realized my mistake. You helped me. Thank you very much.