Is it possible to create types in Julia at runtime?

前端 未结 1 1543
一个人的身影
一个人的身影 2021-02-20 14:38

Let\'s say I want to have a function of the form

abstract RecordType
function CreateRecordType(fields_names::Vector{ASCIIString}, type_name::ASCIIString)
    # m         


        
1条回答
  •  遇见更好的自我
    2021-02-20 15:33

    Approach 1: Parse to get an AST and then eval

    Probably the easiest way is to create a string of what you want and then parse it to get an AST, and then eval the AST. You can do any or all within the function. Here's possible simple implementation that does it all

    function CreateRecordType(typeName::ASCIIString,fieldNames::Array{ASCIIString,1},fieldTypes::Array{ASCIIString,1})
       s::ASCIIString = "type $typeName <: RecordType\n";
    
       for i = 1:length(fieldNames)
          s = s*"$(fieldNames[i])::$(fieldTypes[i])\n"
       end
       eval(parse(s*"end"));
       return;
    end
    

    Using it...

    julia> abstract RecordType;
    
    julia> CreateRecordType("Person",["name","age"],["ASCIIString","Int64"])
    
    julia> bubba = Person("Bubba",2)
    Person("Bubba",2)
    
    julia> print(bubba.age)
    2
    

    That's probably not as efficient as it could be, instead you can take a look at the AST that parse produces and then create the Expr to make the AST directly and not use parse and not use a string.

    Approach 2: Making the AST directly

    Here's an alternate form that creates an AST, it's a little more safe because it requires types and symbols rather than opaque strings. This was created by experimenting with the output of various parses as alluded to above. Using Dict instead of 2 arrays is probably better because the field and the type must always be paired.

    function createTypeAST(typeName::Symbol,parentType::Type,fields::Dict{Symbol,DataType})
       e = Expr(:type,true)
       push!(e.args,Expr(:<:));
       push!(e.args[2].args,typeName);
       push!(e.args[2].args,parentType);
       push!(e.args,Expr(:block))
       for field in fields
          push!(e.args[3].args,:($(field[1])::$(field[2])));
       end
       return e;
    end
    

    2nd form in action

    julia> x = createTypeAST(:P1,RecordType,Dict(:a => Int64))
    :(type P1<:RecordType
            a::Int64
        end)
    
    julia> eval(x)
    
    julia> y = P1(1)
    P1(1)
    
    julia> y.a
    1
    

    0 讨论(0)
提交回复
热议问题