Structs

by Martin D. Maas, Ph.D

Structs are a great way to represent data in a compact and easy-to-understand way. Additionally, there is so much that can be accomplished with just an array of struct.

Defining a struct

In Julia, the struct keyword defines a new Composite Type, based on given field names, and optionally annotated individual types.

By default, structs cannot be modified once initialized (i.e. are inmutable unless explicitly defined as a mutable struct)

Let’s say we want to create a Location type, containing a name, and (lat,lon) coordinates. We can do this as follows:

struct Location
    name::String
    lat::Float32
    lon::Float32
end

To initialize a struct with values, the default constructor is simply using the struct name as you would use a function:

loc1 = Location("Los Angeles", 34.0522,-118.2437)

We can access the struct fields with the dot notation, as is common in several languages:

loc1.name   # "Los Angeles"
loc1.lat    # 34.0522
loc1.lon    # -118.2437

Having defined this Location struct, we can do things like for example defining a vector of Locations called sites, and dynamically fill it with Location elements:

sites = Location[]
push!(sites, Location("Los Angeles", 34.0522,-118.2437))
push!(sites, Location("Las Vegas", 36.1699,-115.1398))

Notice that a very similar result could have been obtained via Named Tuples. Introducing a new Type such as our Location type can be convenient for additional clarity.

Mutable Structs

If we want to be able to modify the components of a struct after it has been initialized, we need to declare a mutable struct, as follows:

mutable struct mLocation
    name::String
    lat::Float32
    lon::Float32
end

We can then do things like:

loc1 = mLocation("Los Angeles", 34.0522,-118.2437)
loc1.name = "LA"

Base.@kwdef: Defaults Values and Keyword-Based Constructors

The Base.@kwdef macro is a helpful tool that enables the use of default values in structs, and also keyword-based constructors.

For example, we can do the following:

Base.@kwdef mutable struct Param
    Δt :: Float64 = 0.1
    n :: Int64
    m :: Int64
end

P = Param(m=50, n=35)

Note: since Julia 1.9, Base exports @kwdef, so you don’t need to add the prefix, and can use @kwdef instead of Base.@kwdef.

Destructuring a Struct

Since Julia 1.7 we a syntax for structs that is very similar to what we had for NamedTuples:

(; n,Δt ) = P

This will get any field of P that matches what we write on the left-hand side and turn it into a variable. Note that the order of the variables doesn’t matter, and that we don’t need to destructure all the fields.

While we can always access the fields of a struct by doing P.Δt or P.n, destructuring the struct enables us to create Δt and n variables automatically. This comes very handy if we have a rather long struct with many fields, and we rather use them as parameters instead.

print("The value of Δt is $(Δt)")
The value of Δt is 0.1