Julia 如何缩短函数体中的类型

Julia 如何缩短函数体中的类型,julia,Julia,最好用一个例子来解释: 我定义了一个类型 type myType α::Float64 β::Float64 end z = myType( 1., 2. ) 然后假设我想将此类型作为参数传递给函数: myFunc( x::Vector{Float64}, m::myType ) = x[1].^m.α+x[2].^m.β (α::Float64, β::Float64) = (m.α, m.β) myFunc( x::Vector{Float64}, α::Flo

最好用一个例子来解释:

我定义了一个类型

type myType
    α::Float64
    β::Float64
end
z = myType( 1., 2. )
然后假设我想将此类型作为参数传递给函数:

myFunc( x::Vector{Float64}, m::myType ) =
    x[1].^m.α+x[2].^m.β
(α::Float64, β::Float64) = (m.α, m.β)
myFunc( x::Vector{Float64}, α::Float64, β::Float64) = x[1].^α+x[2].^β
myFunc( x::Vector{Float64}, m::myType = myFunc(x,m.α,m.β)
是否有一种方法可以传递
myType
,以便我可以在函数体中以“更干净”的方式实际使用它,如下所示:

    x[1].^α+x[2].^β

谢谢您的回答。

您可以将以下内容添加到函数体中:

myFunc( x::Vector{Float64}, m::myType ) =
    x[1].^m.α+x[2].^m.β
(α::Float64, β::Float64) = (m.α, m.β)
myFunc( x::Vector{Float64}, α::Float64, β::Float64) = x[1].^α+x[2].^β
myFunc( x::Vector{Float64}, m::myType = myFunc(x,m.α,m.β)

一种方法是将分派用于更通用的功能:

myFunc( x::Vector{Float64}, m::myType ) =
    x[1].^m.α+x[2].^m.β
(α::Float64, β::Float64) = (m.α, m.β)
myFunc( x::Vector{Float64}, α::Float64, β::Float64) = x[1].^α+x[2].^β
myFunc( x::Vector{Float64}, m::myType = myFunc(x,m.α,m.β)
或者,如果函数较长,则可能需要使用参数。jl的
@unpack

function myFunc( x::Vector{Float64}, m::myType )
  @unpack m: α,β #now those are defined
  x[1].^α+x[2].^β
end
解包的开销很小,因为你没有复制,它只是做了一堆
α=m.α
,这只是做了一个
α
,它指向
m.α
。对于较长的方程,如果您有许多字段并在较长的计算中使用它们,这可能是一种更好的形式(作为参考,我在differentialsequations.jl中经常使用它)

编辑 正如评论中所指出的,还有另一种方法。让我看看这个。您可以使用Parameters.jl中的
@with_kw
宏定义您的类型(带有可选KWARG)。例如:

using Parameters
@with_kw type myType
  α::Float64 = 1.0 # Give a default value
  β::Float64 = 2.0 
end
z = myType() # Generate with the default values
然后您可以使用
@unpack\u myType
宏,该宏由
@with\u kw
宏自动生成:

function myFunc( x::Vector{Float64}, m::myType )
  @unpack_myType m
  x[1].^α+x[2].^β
end

同样,这只会增加在不复制的情况下引用α和β的开销,因此它非常轻量级。

更新:由于一个微妙的原因,我最初的答案是错误的,但我认为这是一个非常有趣的信息,所以我不是完全删除它,而是在留下一个关于它错误原因的解释。非常感谢凤阳指出评估的全球范围!(以及在Expr上下文中使用
$

最初的答复建议:

[eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]
将返回一个列表理解,该列表理解会产生分配副作用,因为它在概念上会导致类似于
[α=1,β=2.,等]
。假设这项任务将在当地范围内。然而,正如所指出的,
eval
总是在全局范围内进行评估,因此上述一条线性规划并没有达到预期的效果。例如:

julia> type MyType
         α::Float64
         β::Float64
       end

julia> function myFunc!(x::Vector{Float64}, m::MyType)
         α=5.; β=6.; 
         [eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]
         x[1] = α; x[2] = β; return x
       end;

julia> myFunc!([0.,0.],MyType(1., 2.))
2-element Array{Float64,1}:
 5.0
 6.0

julia> whos()
                        MyType    124 bytes  DataType
                        myFunc      0 bytes  #myFunc
                             α      8 bytes  Float64
                             β      8 bytes  Float64
也就是说,正如您所看到的,目的是覆盖局部变量α和β,但它们没有覆盖;eval将α和β变量置于全局范围。作为一名matlab程序员,我天真地假设
eval()
在概念上等同于matlab,而没有实际检查。原来它更类似于
evalin('base',…)
命令


再次感谢Fengyand提供了另一个例子,说明为什么“parse and eval”一词对Julia程序员的影响似乎与上面的“it”一词差不多。:)

谢谢-但是还有其他的方法吗?当类型由许多元素组成时,这种方法更方便吗?很好。特别是调度方法,不错的黑客!然而,我得到的印象是,这个问题并不是针对α和β的具体情况,而是“from numpy import*”的概念等价物,您不能手动指定字段名。@unpack是否能够在不指定字段名的情况下解包整个对象?是的。说明有一个神奇的小
@unpack\u MyType
,如果您使用
@和\u kw
定义您的类型,它将已经被定义。然后您只需执行
@unpack\u MyType m
,它就会解压缩该类型。很好,很高兴知道。我会用最后一点更新答案,这似乎正是OP想要的优秀@chrisrackaukas这正是我的目标,非常感谢所有花时间回答这个问题的人。注意:类型的Julia约定是有一个类型的起始大写,即MyType而不是MyType。如果你不想,你不必遵循这一点,只要告诉你。哈,我喜欢样式指南仍然建议使用
cell(n)
,即使他们继续使用并不推荐它:p该链接指向v0.4的样式指南。当
cell
被弃用时,样式指南被更新。很抱歉,我不能同意这个答案。首先,您不应该解析字符串,而应该执行
:($i=$m.$i)
。此外,也许更重要的是,这实际上并没有在本地评估任何东西,评估是在全局范围内的。宏不解析和计算字符串;它们将表达式转换为插入AST的其他表达式。感谢@FengyangWang,我不知道在字符串上下文之外使用
$
,这非常有用!你是说这行在函数中不起作用?我承认我只是在REPL上试过。还有,为什么
$m.$i
而不仅仅是
m.$i
?@FengyangWang谢谢,我已经更新了我的答案。至于
$
方法,我认为您可能想演示一下,而不是提供二手答案:)您好@Tasos,您是对的,它应该是
m.$i
。Julia中有很多地方可以使用
$
;我正在编写一个文档条目,其中包含使用插值的示例。现在,这里有一个简短的描述,可能对我很有用。你在这里学到的东西看起来可以适合一篇好的文档文章