abergmeier
abergmeier

Reputation: 14052

Are nested structs supported in Rust?

When I try to declare a struct inside of another struct:

struct Test {
    struct Foo {}
}

The compiler complains:

error: expected identifier, found keyword `struct`
 --> src/lib.rs:2:5
  |
2 |     struct Foo {}
  |     ^^^^^^ expected identifier, found keyword
help: you can escape reserved keywords to use them as identifiers
  |
2 |     r#struct Foo {}
  |     ^^^^^^^^

error: expected `:`, found `Foo`
 --> src/lib.rs:2:12
  |
2 |     struct Foo {}
  |            ^^^ expected `:`

I could not find any documentation in either direction; are nested structs even supported in Rust?

Upvotes: 69

Views: 54345

Answers (4)

usertt
usertt

Reputation: 11

You can use

[dependencies]
nestify = "0.3"
nestify::nest! {
    #[derive(Debug)] struct Root {
        a: #[derive(Debug)] struct A {
            text: String,
        },
        b: #[derive(Debug)] struct B {
            text: String,
        },
    }
}

Or you can implement one yourself:

macro_rules! nstruct {
    (
        $name:ident {
            $(
                $field_name:ident : $field_ty:ident $({
                    $($field_ty_inner:tt)*
                })?
            ),*
        $(,)? }
    ) => {
        #[derive(Debug)]
        struct $name {
            $(
                $field_name : $field_ty
            ),*
        }

        $(nstruct! {
            $field_ty $({
                $($field_ty_inner)*
            })?
        })*
    };

    ($name:ident {$($fields:tt)*}) => {
        nstruct! {
            struct $name {
                $($fields)*
            }
        }
    };

    ($name:ident) => {};
}


nstruct! {
    Root {
        a: A {
            text: String,
        },
        b: B {
            text: String,
        }
    }
}

Upvotes: 1

Church Zhong
Church Zhong

Reputation: 49

I found a discussion regarding this topic, maybe it can help you: https://internals.rust-lang.org/t/nested-struct-declaration/13314/4

RFC Structural records 592 was discussing the nesting (without the privacy controls or naming), but was ultimately rejected.

// From the RFC (not working as of Rust 1.81.0 in 2024)
struct RectangleTidy {
    dimensions: {
        width: u64,
        height: u64,
    },
    color: {
        red: u8,
        green: u8,
        blue: u8,
    },
}

Below is my old answer, which is the current way to solve it.

Build using the Stable version: 1.65.0. Here's a example for you. rust playground

codes:

#[derive(Debug)]
struct Inner {
    i: i32,
}

#[derive(Debug)]
struct Outer {
    o: i32,
    inner: Inner,
}

pub fn test() {
    // add your code here
    let obj = Outer {
        o: 10,
        inner: Inner { i: 9 },
    };
    assert!(10i32 == obj.o);
    assert!(9i32 == obj.inner.i);
    println!("{}", obj.o);
    println!("{}", obj.inner.i);
    println!("{:?}", obj);
}
fn main() {
    test();
}

Upvotes: 3

Caesar
Caesar

Reputation: 8494

They are not supported by Rust.

But you can write yourself a proc macro that emulates them. I have, it turns

structstruck::strike!{
    struct Test {
        foo: struct {}
    }
}

into

struct Foo {}
struct Test {
    foo: Foo,
}

You haven't explicitly said so, but I suspect that your goal for using nested structs is not more easily readable data structure declarations, but namespacing? You can't actually have a struct named Test and access Foo as Test::Foo, but you could make yourself a proc macro that at least automatically creates a mod test { Foo {} }.

Upvotes: 0

Vladimir Matveev
Vladimir Matveev

Reputation: 127781

No, they are not supported. You should use separate struct declarations and regular fields:

struct Foo {}

struct Test {
    foo: Foo,
}

Upvotes: 72

Related Questions