---
title: "Structs and Enums"
description: "Declaring named structures and enumerations."
---
import SC from '@slint/common-files/src/components/SC.astro';
import OnlyInSC from '@slint/common-files/src/components/OnlyInSC.astro';

<SC>
## Structs

A `struct` declaration at the top level of a `.slint` source file defines a named structure type;
its fields are written between braces, each a name and a type separated by `:`,
the fields separated by commas, and a struct with no fields is allowed. \{#sls.struct.decl}

Each field's type can be any property type. \{#sls.struct.field-type}

```slint
export struct Palette {
    fill: color,
    gap: length,
}
```

<OnlyInSC>
A field shall not declare a default value. \{#sls.struct.no-field-default}

The default value of a struct is the value whose every field holds the default value of its type. \{#sls.struct.default}
</OnlyInSC>
</SC>

A `;` between fields is a compile error; the compiler tells you to use `,` instead.

A struct may be prefixed with one or more `@rust-attr(...)` attributes and may be `export`ed.
Declaring a struct whose name matches an already-defined type replaces the earlier type and emits a warning.

### Constructing and accessing

<SC>
A struct value is written as a struct literal that initializes fields by name,
`{ field1: value1, field2: value2 }`, with an optional trailing comma. \{#sls.struct.literal}

<OnlyInSC>
A struct literal shall initialize every field of the struct exactly once,
and shall not name a member that the struct does not have. \{#sls.struct.literal.exact}
</OnlyInSC>

A field is read with the `.` operator, as in `palette.fill`. \{#sls.struct.field-access}

```slint
export struct Palette {
    fill: color,
    gap: length,
}

export component Example inherits Window {
    out property <Palette> palette: { fill: #f00, gap: 2px };
    out property <color> tint: palette.fill;
}
```
</SC>

A struct literal need not list every field; an omitted field takes its default value,
and members that don't name a field of the target struct are ignored.
`{}` lists no field at all, so every field takes its default value.

The default value of a struct has every field set to its own default value, unless the field declares its own.

### Field default values

`= expression` after a field's type declares a default value for that field:

```slint
export struct Player {
    name: string = "unknown",
    score: int = 100,
}

export component Example {
    // player.name is "Foo", player.score is 100
    in-out property<Player> player: { name: "Foo" };
}
```

The expression must be a compile-time constant.
It may combine literals, casts, and operators, but referencing a property, an element, or any runtime value
is a compile error.
A number is only converted to a string when the result is the same in every locale:
`= 42` is fine, while `= 42.1` is a compile error, because the decimal separator depends on the locale.

The default applies whenever an instance of the struct is created without a value for the field:
in struct literals that omit the field, in properties of that struct type that are never set,
and when the struct is constructed from native code
(Rust `Player::default()`, C++ `Player{}`, JavaScript `new ui.Player()`, Python `ui.Player()`).

Field default values are only supported in named struct declarations.
Writing `= expression` in an anonymous struct type is a compile error.

### Anonymous structures

`{ identifier1: type1, identifier2: type2 }` is an anonymous struct type.
It behaves like a named struct without a name:

```slint
export component Example {
    in-out property<{name: string, score: int}> player: { name: "Foo", score: 100 };
    in-out property<{a: int, }> foo: { a: 3 };
}
```

Two anonymous struct types with the same fields are the same type.
A named struct is only ever equal to itself: it is not interchangeable with an anonymous struct of identical fields.

<SC>
## Enums

An `enum` declaration at the top level defines an enumeration;
its values are listed between braces, separated by commas. \{#sls.enum.decl}

An enum shall have at least one value. \{#sls.enum.nonempty}

A value shall not have the same name as the enum. \{#sls.enum.value-name}

The values shall be distinct; `-` and `_` are the same character within a name,
so `hello-world` and `hello_world` name one value. \{#sls.enum.distinct}

No two values shall map to the same generated name, formed by dropping `-` and `_`
and capitalizing the first letter of the name and of each word after a separator.
`hello-world` and `HelloWorld` are different values but map to the same name,
so an enum cannot declare both. \{#sls.enum.name-collision}

```slint
export enum Direction { up, down, left, right }

export component Example inherits Window {
    in-out property<Direction> heading: Direction.up;
}
```

An enum value is referenced with the enum name and the value name separated by a dot,
as in `Direction.up`. \{#sls.enum.value}

The default value of an enum is its first value. \{#sls.enum.default}
</SC>

### Omitting the enum name

The enum name may be omitted wherever a value of that enum type is the expected type:
in a binding, a struct field, an array element, a function or callback argument, and a return value.

```slint
export enum CardSuit { clubs, diamonds, hearts, spade }
export struct Card { suit: CardSuit, value: int }

export component Example {
    // in a struct field and an array element
    out property<Card> card: { suit: hearts, value: 10 };
    out property<[CardSuit]> deck: [clubs, diamonds, hearts, spade];

    pure function is-red(suit: CardSuit) -> bool {
        return suit == hearts || suit == diamonds;
    }
    // as a function argument
    out property<bool> spade-is-red: is-red(spade);
}
```

In a comparison the name may be omitted only on the right-hand side, which takes the type of the left:
`card.suit == hearts` works, but `hearts == card.suit` does not, because the left operand has no expected type.