VarStructs are similar to structs but have extra features:
- You can add fields after their definition.
- They can be defined inside a function or a local scope.
- They can be redefined.
- Fields can be uninitialized, have default values, etc.
Similar to structs
- They can be used for dispatching (zero-cost)
- They can have custom constructors
- They have type conversion/checking for the fields that are declared
VarStructs removes the limitations of structs, and so in addition to all the applications of structs, you can use structures in new applications! For example, it can be used to define a "Schema" for your type, or you can used it for serialization of unknown data.
SharedVarStructs also allows having shared instances for one struct.
using Pkg; Pkg.add("VarStructs")
using VarStructs
If you want to see a full example see here.
There are two ways to declare them:
In this syntax, providing initial values and types for the fields are optional.
@var struct Animal
name::String
number::Int64
end
You can redeclare the struct later, but in redeclaration you will not get type checking based on the previous declaration.
In this syntax, you should provide the initial values for the fields. Providing type for the fields are optional (if not provided, it is considered as Any
).
@var Person(
name = "Amin",
number::Float64 = 20.0,
)
Use the following syntax for getting an instance:
julia> person = Person(name = "Amin", number = 20.0)
Person(
name::Any = Amin,
number::Float64 = 20.0,
)
# Type conversion for the fields that were declared
julia> person2 = Person(name = "Amin", number = 20) # number is converted to Float64
Person(
name::Any = Amin,
number::Float64 = 20.0,
)
# Type checking for the fields that were declared
julia> person2 = Person(name = "Amin", number = "20")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64
# new field added
julia> person2 = Person(name = "Amin", number = 20.0, initial = "A")
Person(
initial::String = A,
name::Any = Amin,
number::Float64 = 20.0,
)
The two syntaxes that are used for declaration also return an instance of the VarStruct. So if you need an instance right away, you can use the following.
animal = @var Animal(
name = "lion",
number::Int64 = 10,
)
# redefinition of `Animal` returns a new instance:
animal2 = @var Animal(
name = "dog",
number::Int64 = 1,
)
# Accessing
julia> person.name
"Amin"
# Setting
julia> person.name = "Tim"
# Adding Fields
julia> person.initial = "T"
info
function dispatch for Person
and Animal
type:
function info(x::Person)
println("Their home is city")
return x.name
end
function info(x::Animal)
println("Their home is jungle")
return x.name
end
julia> info(person)
"Their home is city"
"Amin"
julia> info(animal)
"Their home is jungle"
"lion"
To define a custom constructor return an instance using keyword method:
function Person(name, number)
return Person(
name = name,
number = number,
initial = name[1],
)
end
Person("Amin", 20.0)
Using @shared_var
, you can define make the struct shared. That means calling the constructor for creating a new instance will use the already defined instance as its declaration.
person = @shared_var Citizen(
name::String = "Amin",
number::Float64 = 20.0,
)
person2 = Citizen(name = "Not-Amin", number = 1) # Will make "person" the same as "person2"
If you are a geek see here too: ReadmeGeeks