Is it possible to implement a type factory in Julia without using `eval()`?
例如,我有一个基本类型的抽象类型,我想实现一个类型工厂,它动态地在这个抽象类型下创建具体的类型,名称(和其他类型特征)由用户输入参数提供。
1 2 3 4 5 6 | abstract type AbstractFoo end function TypeFactory(typename::String, supertype::DataType) ... return ConcreteSubtype end |
函数
我知道这种类工厂在Python中实现并不太困难(例如,如何从基类动态创建派生类)。在Julia中,可以通过使用
编辑[2018年2月8日]:
我不善于表达清楚。我刚认识茱莉亚,最近刚开始用它编写我的项目。我知道继承权是不受支持的,也不打算在茱莉亚继承。
从python的背景来看,我觉得
"用户输入"并不仅仅指命令行输入。它们可以由用户的配置文件提供。(这就是说,@salchipapa的宏观解决方案既贴切又优雅!)
Is it possible to implement a type factory in Julia without using
eval() ?
可以使用宏:
- https://docs.julialang.org/en/stable/manual/metaprogramming/man-macros-1
Macros provide a method to include generated code in the final body of a program. A macro maps a tuple of arguments to a returned expression, and the resulting expression is compiled directly rather than requiring a runtime
eval() call.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | julia> VERSION v"0.7.0-DEV.2098" julia> module Factory export @factory macro factory(type_name::Symbol, super_type::Symbol) # ... return quote struct $type_name <: $(esc(super_type)) # ... bar end return $(esc(type_name)) end end end Main.Factory julia> using Main.Factory: @factory julia> abstract type AbstractFoo end julia> @factory ConcreteFoo AbstractFoo ConcreteFoo julia> foo = ConcreteFoo(42) ConcreteFoo(42) julia> foo.bar 42 julia> ConcreteFoo <: AbstractFoo true julia> supertype(ConcreteFoo) AbstractFoo |
根据评论中的@gnimu理解,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | julia> module Factory export @factory function input(prompt::String="")::String print(prompt) return chomp(readline()) end macro factory(type_name = input("Type name:")) AbstractT = Symbol(:Abstract, type_name) ConcreteT = Symbol(:Concrete, type_name) return quote abstract type $(esc(AbstractT)) end struct $ConcreteT <: $(esc(AbstractT)) bar end return $(esc(AbstractT)), $(esc(ConcreteT)) end end end Main.Factory julia> using Main.Factory: @factory julia> @factory Type name: Foo (AbstractFoo, ConcreteFoo) julia> @factory Type name: Bar (AbstractBar, ConcreteBar) julia> @factory Baz (AbstractBaz, ConcreteBaz) julia> foo = ConcreteFoo(42) ConcreteFoo(42) julia> foo.bar 42 julia> ConcreteFoo <: AbstractFoo true julia> supertype(ConcreteFoo) AbstractFoo julia> @macroexpand @factory Type name: Qux quote #= REPL[1]:13 =# abstract type AbstractQux end #= REPL[1]:14 =# struct ConcreteQux <: AbstractQux #= REPL[1]:15 =# bar end #= REPL[1]:17 =# return (AbstractQux, ConcreteQux) end julia> eval(ans) (AbstractQux, ConcreteQux) |