Reputation: 421
I want to create a struct with many properties, but when applying the functions, I want it to behave like its type is one of the selected properties, for example:
mutable struct Field{T}
field_type::T
field_description::String
end
I want this struct to behave as the T type, if I assign it a String, when doing print(Field{String}("Hello", "World"))
I want it to print Hello
, if field type is a Int8
I want to be able to do Field{Int8}(1, "First term") + Field{Int8}(1,"Second term")
and get 2
and so on. Is this possible somehow?
For more context, I want this to add some metadata to the Field Type, but it has to behave as the chosen field_type
Upvotes: 1
Views: 345
Reputation: 42214
I would consider usingBase.@kwdef
or a better equivalent in the Parameters
package.
Base.@kwdef struct Field{T}
field::T
description::Union{String,Nothing} = nothing
end
And now:
julia> Field(field=1)
Field{Int64}(1, nothing)
or:
using Parameters
@with_kw struct Field2{T}
field::T
description::Union{String,Nothing} = nothing
end
And now:
julia> Field2(field=1)
Field2{Int64}
field: Int64 1
description: Nothing nothing
However if you do not want to provide the name you can do:
julia> struct Field3{T}
field::T
description::Union{String, Nothing}
Field3(field::T, description=nothing) where T = new{T}(field, description)
end
And now you can just do:
julia> Field3(11)
Field3{Int64}(11, nothing)
Upvotes: 0
Reputation: 12654
You are over-complicating things. You just need to realize that Field{String}
and Field{Int8}
are two separate types, and treat them as such.
For example:
foo(f::Field{String}) = do_something()
foo(f::Field{Int8}) = do_something_else()
So for printing and adding, define:
Base.show(io::IO, f::Field{String}) = show(io, f.field_type)
Base.:+(f1::Field{Int8}, f2::Field{Int8}) = f1.field_type + f2.field_type
You could make it more generic by defining
Base.show(io::IO, f::Field{<:AbstractString}) = show(io, f.field_type)
Base.:+(f1::Field{<:Number}, f2::Field{<:Number}) = f1.field_type + f2.field_type
instead.
I defined show
instead of print, since that is more convenient, but you can define any methods for any Field{T}
that you like. Just remember that different T
gives different types, and it's easy.
I would recomment that you create another convenience constructor:
Field(x::T, d) where {T} = Field{T}(x, d)
Now you don't need to specify T
in the constructor call:
1.7.2> f1 = Field("Hello", "World"); typeof(f1)
Field{String}
1.7.2> f2 = Field(Int8(1), "World"); typeof(f2)
Field{Int8}
1.7.2> print(f1)
"Hello"
1.7.2> f2 + f2
2
Upvotes: 1