0

I want to create a struct by calling new member function of a given struct by initializing only some of the fields. I am getting an error error[E0063]: missing fields b and join_handle in initializer of B::B. This is my sample code

main.rs

mod B;
mod A;

fn main() {
    println!("Hello, world!");
}

A.rs

pub struct AS {
    a: String
}

B.rs

use crate::A::AS;
use std::thread;

pub struct B {
    a: String,
    b: AS,
    join_handle: thread::JoinHandle<()>
}

impl B {
    fn new() -> B {
        B {
            a: String::from("Hi"),
        }
    }
}

How to partially initialize a struct?

Harry
  • 2,177
  • 1
  • 19
  • 33
  • 3
    Rust does not have partial initialization of structs. – PitaJ Dec 02 '22 at 18:45
  • 1
    To clarify: Safe Rust guarantees all variables are initialized before they are read, therefore it **requires** that structs be fully initialized when they are created. – effect Dec 02 '22 at 22:36
  • https://stackoverflow.com/questions/61264223/why-must-be-structure-initialized-in-rust – effect Dec 02 '22 at 22:50
  • If you're ready to use `unsafe` code (don't unless benchmarking shows a bottleneck and you're not a beginner) you need to use `MaybeUninit`. If not, use `Option`s. – Chayim Friedman Dec 04 '22 at 04:34

2 Answers2

3

You can't partially initialize a struct. You could just use Options inside of B:

struct B {
    a: String,
    b: Option<AS>,
    join_handle: Option<thread::JoinHandle<()>>,
}
impl B {
    fn new() -> Self {
        Self {
            a: String::from("hi"),
            b: None,
            join_handle: None,
        }
    }
}

Or use a builder instead:

use std::thread;
fn main() {
    println!("Hello, world!");
}

pub struct AS {
    a: String
}

pub struct B {
    a: String,
    b: AS,
    join_handle: thread::JoinHandle<()>
}

impl B {
    fn builder() -> BBuilder {
        BBuilder {
            a: String::from("Hi"),
            b: None,
            join_handle: None,
        }
    }
}

struct BBuilder {
    a: String,
    b: Option<AS>,
    join_handle: Option<thread::JoinHandle<()>>,
}

impl BBuilder {
    fn a(mut self, b: AS) -> Self {
        self.b = Some(b);
        self
    }
    fn join_handle(mut self, join_handle: thread::JoinHandle<()>) -> Self {
        self.join_handle = Some(join_handle);
        self
    }
    fn build(self) -> Option<B> {
        let Self{ a, b, join_handle } = self;
        let b = b?;
        let join_handle = join_handle?;
        Some(B { a, b, join_handle })
    }
}
cafce25
  • 15,907
  • 4
  • 25
  • 31
2

You don't. You can't partially initialize anything in Rust.

Maybe you need to make some of the fields optionals.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 1
    I want to initialize remaining fields at a later stage, let's say the `join_handle` member by calling the method `start` which spawns a thread – Harry Dec 02 '22 at 18:50