typeof(a) and typeof(b) here do not tell you anything about performance of those types. Test1 and Test2{Float64} are essentially just the names of the structs (a.k.a. types) you defined. In the Test3 example below, I get the same output from typeof as your Test2, but Type3 will perform badly because 2/3 of the fields are abstractly typed.
julia> struct Test3{T}
a::Real
b::T
c::AbstractString
end
julia> c = Test3(5.5, 5.6, "hello")
Test3{Float64}(5.5, 5.6, "hello")
julia> typeof(c)
Test3{Float64}
The point is that you want the fields of your struct to have concrete types (not abstract types). If you only need to allow Float64, then it is fine to assign that type to a field directly. Parametric types allow the definition of multiple concrete types at once. The example below will be concretely typed parametrically.
julia> struct Test4{T}
a::T
b::T
c::String
end
julia> Test4(5.5, 5.6, "hello")
Test4{Float64}(5.5, 5.6, "hello")
julia> Test4("hello", "welcome", "home")
Test4{String}("hello", "welcome", "home")
The struct Test5 below is exactly the same as Test4 above except that Test5 will error if I try to enter something other than a subtype of Real for the first two fields. There is no performance difference.
julia> struct Test5{T <: Real}
a::T
b::T
c::String
end
julia> Test5(5.5, 5.6, "hello")
Test5{Float64}(5.5, 5.6, "hello")
julia> Test5("hello", "welcome", "home")
ERROR: MethodError: no method matching Test5(::String, ::String, ::String)
Closest candidates are:
Test5(::T, ::T, ::String) where T<:Real at REPL[12]:2
Stacktrace:
[1] top-level scope
@ REPL[14]:1