missing struct fields error while creating an instance of struct [duplicate] - rust

This question already has answers here:
How are you able to create partially initialised structs?
(3 answers)
Why must be structure initialized in rust?
(2 answers)
Closed last month.
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?

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 })
}
}

You don't. You can't partially initialize anything in Rust.
Maybe you need to make some of the fields optionals.

Related

Rust: error: "returns a value referencing data owned by the current function"

I think this is a kind of common questions. I've read some solutions but my situation is a bit different...
It complains at line 8. However, I can't change the function signature of new_b as well as everything below the common line. They are all external packages.
So how can I design the function new_a to workaround?
fn main() {
new_a();
}
fn new_a() -> A<'static> {
let b = B {};
A { c: new_b(&b) }
}
pub struct A<'a> {
c: C<'a>,
}
// Below are exteral packages
fn new_b<'a>(b: &'a B) -> C<'a> {
C { b: &b }
}
pub struct B {}
pub struct C<'a> {
b: &'a B,
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=160e63f1300506472b7c1b0811b37453

Heterogeneous collection as a member of a class in Rust

I am new to Rust, and does not fully understand lifetime, so probably, that is why I can't solv the following issue. I need a solution in which a class has a heterogeneous HashMap containing different objects derived from the same trait.
I have to be able to extend an object with some (multiple) functionality dinamically. Other solutions are also welcome. Adding functionality to the class in compile time could also work, but adding functionality directly to the main class not.
use std::collections::HashMap;
trait DoerTrait {
fn do_something( & self, a : u8, b : u8 ) -> u8;
}
struct MyDoer<'a> {
}
impl DoerTrait for MyDoer<'a> {
fn do_something( & self, a : u8, b : u8 ) -> u8 {
return a + b;
}
}
struct MyMain<'a> {
doers : HashMap<u8,&'a dyn DoerTrait>,
}
impl<'a> MyMain<'a> {
fn new() -> Self {
Self {
doers : HashMap::new()
}
}
fn add_doer( &mut self, id : u8, doer : & dyn DoerTrait ) {
self.doers.insert( id, doer );
}
fn do_something( & self, id : u8 ) {
match self.doers.get( &id ) {
Some( doer ) => {
println!( "{}", doer(19,26) );
}
None => {
println!( "Doer not specified!" );
}
}
}
}
fn main() {
let mut mymain = MyMain::new();
let mydoer = MyDoer{};
mymain.add_doer( 42, &mydoer );
mymain.do_something( 42 );
}
Not too sure what issue you have, once MyDoer has been stripped of its incorrect (unnecessary) lifetime and the lifetime has correctly been declared on impl MyMain, the compiler directly points to the parameter of add_doer not matching (after which it points out that doer in do_something is not a function):
use std::collections::HashMap;
trait DoerTrait {
fn do_something(&self, a: u8, b: u8) -> u8;
}
struct MyDoer;
impl DoerTrait for MyDoer {
fn do_something(&self, a: u8, b: u8) -> u8 {
return a + b;
}
}
struct MyMain<'a> {
doers: HashMap<u8, &'a dyn DoerTrait>,
}
impl<'a> MyMain<'a> {
fn new() -> Self {
Self {
doers: HashMap::new(),
}
}
fn add_doer(&mut self, id: u8, doer: &'a dyn DoerTrait) {
self.doers.insert(id, doer);
}
fn do_something(&self, id: u8) {
match self.doers.get(&id) {
Some(doer) => {
println!("{}", doer.do_something(19, 26));
}
None => {
println!("Doer not specified!");
}
}
}
}
fn main() {
let mut mymain = MyMain::new();
let mydoer = MyDoer {};
mymain.add_doer(42, &mydoer);
mymain.do_something(42);
}

How to store a field that only take reference to String created in `::new()`?

In the below code, how should I store a B field in A? Supposed that I can not change the definition of B.
As a newbie to Rust, I searched Google and most of them explain why the error happens. I could understand the compile error, but I can't figure out how to fix it. Or is it bad design to store the field in this case? Are there other solutions to this?
Thanks!
use std::io::Read;
struct A<'a> {
b: B<'a>,
}
impl<'a> A<'a> {
pub fn new(mut reader: impl Read) -> Self {
let mut s = String::new();
reader.read_to_string(&mut s);
let b = B { b: &s };
A { b }
}
}
// From 3rd party library, can't change the struct!
struct B<'a> {
b: &'a str,
}
fn main() {}
Well, in this case you need something to own the data. So just make your A to own it, and then have a method that creates the B type from A:
struct A {
s: String,
}
// From 3rd party library, can't change the struct!
struct B<'a> {
b: &'a str,
}
impl A {
pub fn new(mut reader: impl Read) -> Self {
let mut s = String::new();
reader.read_to_string(&mut s);
A { s }
}
fn as_b(&self) -> B {
B { b: &self.s }
}
}
Playground

Is it possible to pass a function receiving self as a parameter of a function of self?

Can I pass a function of an instance as a parameter to a function of the same instance, or do I have to pull the passed function out of the instance?
So, basically, does something like this work:
struct Some_Type {
}
impl Some_Type {
pub fn new() -> Self {
Some_Type{}
}
fn some_fn(&self, value: u32) -> u32 {
value
}
fn some_other_fn(&self, value: u32, input_fn: &dyn Fn(&Self, u32) -> u32) -> u32 {
input_fn(self, value)
}
}
fn main() {
let instance = Some_Type::new();
let fourty_two = instance.some_other_fn(42, &instance.some_fn);
}
Or do I have to write it like this:
struct Some_Type {
}
impl Some_Type {
pub fn new() -> Self {
Some_Type{}
}
fn some_other_fn(&self, value: u32, fn: &dyn Fn(&Self, u32) -> u32) -> u32 {
fn(value)
}
}
fn some_fn(&Some_Type, value: u32) -> u32 {
value
}
fn main() {
let instance = Some_Type::new();
let fourty_two = instance.some_other_fn(42, &some_fn);
}
I found a solution myself. One can write
fn main() {
let instance = Some_Type::new();
let fourty_two = instance.some_other_fn(42, &Some_Type::some_fn);
}
and pass &self to fn inside Some_Type.some_other_fn in the first example.

How can I override all the fields in a mutable reference using another struct?

How can I avoid listing all the fields when using x to populate input?
struct StructX {
a: u32,
b: u32,
}
trait TraitY {
fn foo(info: &mut StructX) -> bool;
}
impl TraitY for SomeZ {
fn foo(input: &mut StructX) -> bool {
let mut x = StructX { /*....*/ };
// do something with x, then finally:
input.a = x.a;
input.b = x.b;
}
}
In C++ it would be just input = x, but that doesn't work in Rust. Note that this is an "interface" so I cannot change the type of input to something else.
You have to dereference input (playground):
struct StructX {
a: u32,
b: u32,
}
trait TraitY {
fn foo(info: &mut StructX) -> bool;
}
impl TraitY for SomeZ {
fn foo(input: &mut StructX) -> bool {
let mut x = StructX { /*....*/ };
// do something with x, then finally:
*input = x;
return true;
}
}
If you wouldn't like to move x into input then you can use Clone::clone_from
playground
#[derive(Clone)]
struct StructX {
a: u32,
b: u32,
}
trait TraitY {
fn foo(info: &mut StructX) -> bool;
}
struct SomeZ{}
impl TraitY for SomeZ {
fn foo(input: &mut StructX) -> bool {
let mut x = StructX { a:42, b:56};
x.a = 43;
input.clone_from(&x);
return true;
}
}

Resources