是否可以在运行时在Julia中创建类型?

是否可以在运行时在Julia中创建类型?,julia,Julia,假设我想要一个形式的函数 abstract RecordType function CreateRecordType(fields_names::Vector{ASCIIString}, type_name::ASCIIString) # magic that creates the type type_name with string fields field_names end 例如,CreateRecordType([“name”,“age”],“Person”)将创建具有以下定

假设我想要一个形式的函数

abstract RecordType
function CreateRecordType(fields_names::Vector{ASCIIString}, type_name::ASCIIString)
    # magic that creates the type type_name with string fields field_names
end
例如,
CreateRecordType([“name”,“age”],“Person”)
将创建具有以下定义的新类型:

type Person <: RecordType
    name::ASCIIString
    age::ASCIIString
end
键入Person方法1:解析以获取AST,然后进行eval
可能最简单的方法是创建一个您想要的字符串,然后解析它以获得AST,然后评估AST。您可以在函数中执行任何或所有操作。这里有一个可能的简单实现,它可以完成所有这些

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
这可能没有可能的那么有效,相反,您可以查看一下parse生成的AST,然后创建Expr来直接生成AST,而不使用parse,也不使用字符串

方法2:直接制作AST 这里有一个创建AST的替代表单,它更安全一些,因为它需要类型和符号,而不是不透明的字符串。这是通过实验上面提到的各种解析的输出而创建的。使用Dict而不是2个数组可能更好,因为字段和类型必须始终成对

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
函数createTypeAST(typeName::Symbol,parentType::Type,fields::Dict{Symbol,DataType}) e=Expr(:type,true) 推(e.args,Expr(:x=createTypeAST(:P1,RecordType,Dict(:a=>Int64)) :(P1类评估(x) julia>y=P1(1) P1(1) 朱莉娅>y.a 1.
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
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