如何根据 Julia 中的符号数组操作变量的值?

How to manipulate the value of variables based on an array of symbols in Julia?

这与大卫的问题here有些相关。我感兴趣的是遍历符号数组(指向对象)并对循环的每一步执行操作。例如,假设我想编写一个函数来查看一堆变量并将任何标量转换为单元素数组。

widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"

theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
    if !(typeof(eval(thisVariable)) <: Array)
        println("Found a scalar")
        #Make it a vector here 
    end
end

理想情况下,在这结束时我们会有以下内容

widget = ["a scalar"]
dohickey = ["item 1", "item 2"]
gizmo = ["another scalar"]

这是一个相当蹩脚的例子,但如何做到这一点?我想我应该可以使用

:($thisVariable) = [:($thisVariable)]

但我无法让它工作。

编辑:下面的 DSM 解决方案适用于上述情况,但在我的实际使用中,我想在函数内执行此操作。如果我定义

function getsort(; arga="", argb="", argc="")
    filterSpecs = [:arga, :argb, :argc]
    for ts in filterSpecs
        if !(typeof($ts) <: Array)
            #nothing here
        end
    end
end

然后调用它抛出的 getsort()

error compiling getsort: error compiling __getsort#31__: syntax: prefix $ in non-quoted expression

我显然遗漏了一些关于元编程魔术的东西。

根据文档的 code generation 部分,我认为您只需要

    @eval $thisVariable = [$thisVariable]

例如:

widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"

theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
    if !(typeof(eval(thisVariable)) <: Array)
        println("Found a scalar")
        @eval $thisVariable = [$thisVariable]
    end
end

这给了我

Found a scalar
Found a scalar

julia> widget
1-element Array{ASCIIString,1}:
 "a scalar"

julia> dohickey
2-element Array{ASCIIString,1}:
 "item 1"
 "item 2"

julia> gizmo
1-element Array{ASCIIString,1}:
 "another scalar"

这更像是@DSM 回答的后续,但在注释中编写代码很难。提醒一句:eval 在全局范围内计算,这可能会导致奇怪的事情

julia> a = 3
3

julia> function f(a)
         eval(:(a = 1))
         println(a)
       end
f (generic function with 1 method)

julia> f(a)
3

julia> a
1

你确定你需要一个宏吗?如果你只想处理你的函数输入,你可以这样做:

julia> function newDictOfArrays(d)
         wrapped=false
         for (k,v) in d
           if !(typeof(v) <: AbstractArray)
             wrapped = true
             d[k] = [v]
           end
         end
         (wrapped, d)
       end
newDictOfArrays (generic function with 1 method)

julia> function f(; kwargs...)
         (wrapped, d) = newDictOfArrays(Dict(kwargs))
         if wrapped
           return f(;d...)
         end
         println("continue knowing all keyword args have been wrapped: $kwargs")
       end
f (generic function with 1 method)

julia> f(a=1, b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]

julia> f(a=[1], b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]

newDictOfArrays 检查字典的所有成员是否有不是 AbstractArray 子类型的值,并用包装值覆盖该项目。在 f 中,如果有任何内容被包装,它会使用作为关键字参数传递的新字典再次调用相同的函数。没有宏、eval 等,但如果经常需要,您可以考虑编写一个自动将代码注入 f 的宏。