Smart-contract development

struct

A struct bundles several related variables into one named record — think of a single row of a table, like a Position with an owner address, a deposit amount, and an expiry time grouped together. Defining a struct gives you a custom composite type you can store, pass around, and put inside arrays and mappings, instead of juggling parallel loose variables.

In storage, a struct's fields are laid out in declaration order, and the EVM tries to pack small fields together: several values that fit consecutively within a 32-byte slot (for example a uint128, a uint64, and a bool) share one slot, while a field that would overflow the current slot starts a fresh one. Reordering fields so small ones sit next to each other is a classic gas optimization, because each storage slot written costs an SSTORE. Dynamic members (a mapping or a dynamically sized array inside the struct) occupy their own slot that points to a hash-derived location.

Across the rest of the language a struct behaves like the data location it sits in: a storage struct copied into memory copies every field (costing gas), while a memory struct passed to an internal function is passed by reference. A mapping may only appear as a struct member when the struct is in storage. Over the ABI a struct is encoded as a tuple, so external callers see its fields in order, not its name.

struct Packed {     // 1 slot: 128 + 64 + 8 bits all fit in 256
  uint128 a;
  uint64  b;
  bool    c;
}
struct Loose {      // 3 slots: the uint256 splits the small fields
  uint128 a;
  uint256 big;
  uint128 d;
}

Same data, two layouts, very different storage cost.

Field order matters for cost, not correctness: declaring small types adjacently can collapse three storage slots into one and cut writes from three SSTOREs to one.