我有一个字符串x
。我认为x
是类型的字符串表示形式,是Number
的子类型。例如,x
可能会使用值"Float64"
。我可以使用以下方式检查:
eval(parse(x)) <: Number
但是,x
可能包含某些危险内容,例如"rm(something_important)"
上的某些变体,因此在我确定eval
之前使用x
是一个坏主意安全
有什么方法可以安全地检查x
是否是Number
子类型的字符串表示形式?
(除了构建Number
所有可能子类型的字符串数组并进行比较...)
答案 0 :(得分:4)
HDF5.jl包必须处理这个问题。 It tackles it解析字符串,然后在 eval
之前检查结果。如果解析后的字符串是它认为是valid_type_expression
的字符串,那么它知道在Main
命名空间中进行评估应该是安全的。这允许它从主命名空间中拾取自baremodule
中无法使用的自定义类型。
更多细节:解析任意字符串后,您可以检查返回的对象以查看它是否“安全”进行评估:
julia> dump(parse("Int"))
Symbol Int
julia> dump(parse("Vector{Int}"))
Expr
head: Symbol curly
args: Array(Any,(2,))
1: Symbol Vector
2: Symbol Int
typ: Any
julia> dump(parse("""rm("/")"""))
Expr
head: Symbol call
args: Array(Any,(2,))
1: Symbol rm
2: ASCIIString "/"
typ: Any
我们希望确保我们永远不会eval
一个可以调用任意行为的表达式。根据您希望支持类型语法的完整程度,您的解决方案可能非常简单,也可能与我上面链接的HDF5解决方案一样复杂。如果你只是简单的,未参数化的类型,我们可以大大简化:
is_valid_type_expression(ex::Symbol) = true
is_valid_type_expression(ex) = false
function julia_type(string)
ex = parse(string)
if is_valid_type_expression(ex)
try
typ = eval(Main, ex)
isa(typ, Type) && typ <: Number && return typ
end
end
error("unsupported type: $string")
end
julia> julia_type("String")
ERROR: unsupported type: String
in julia_type at none:9
julia> julia_type("Int")
Int64
julia> julia_type("""rm("/")""")
ERROR: unsupported type: rm("/")
in julia_type at none:9
请注意,任何比符号更复杂的内容都不允许为eval
。在eval
表达式之后,我们检查以确保类型是Type,并且它是Number
的子类型。除了内置的子类型之外,这还将允许Number
的自定义子类型,因为我们正在Main
命名空间中对其进行评估。
答案 1 :(得分:2)
修改:此解决方案不安全。阅读评论。我离开它是因为它仍然具有指导性。
eval
可选择将模块作为其第一个参数。
您可以在裸模块(baremodule
)中对其进行评估,因此命令无法访问标准库(然后它不会造成太大的伤害)。
julia> baremodule M
end
julia> x = :(rm("/"))
:(rm("/"))
julia> eval(M, x)
ERROR: rm not defined
julia> x = :"Float64"
"Float64"
julia> eval(M, x)
"Float64"