如何kwargs在Julia函数中使用并声明其类型的速度?
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c::Float64 = kwargs[:c]
else
c::Float64 = 1.0
end
return x^2 + c
end
f(0.0, c=10.0)
Run Code Online (Sandbox Code Playgroud)
收益率:
ERROR: LoadError: syntax: multiple type declarations for "c"
Run Code Online (Sandbox Code Playgroud)
当然我可以定义函数f(x::Float64, c::Float64=1.0)来实现结果,但是我有许多可选参数,默认值要传递,所以我更喜欢使用kwargs.
谢谢.
正如另一个答案中所指出的,这真的唯一的问题是如果你的类型不稳定.如果你这样做,答案就是分层你的功能.有一个顶层进行类型检查和各种设置,然后调用一个使用dispatch快速的函数.例如,
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = kwargs[:c]
else
c = 1.0
end
return _f(x,c)
end
_f(x,c) = x^2 + c
Run Code Online (Sandbox Code Playgroud)
如果你的大部分时间花在内部函数上,那么这将更快(它可能不是非常简单的函数).这也允许非常一般的使用,默认情况下你有一个关键字参数nothing,if nothing ...并且可以设置一个复杂的默认值,而不必担心类型稳定性,因为它将被屏蔽内部函数.
在性能敏感的内部函数之上的这种高级类型检查包装在DifferentialEquations.jl中被大量使用.查看SDE求解器的高级包装器,通过确保类型稳定性(内部函数是sde_solve)来获得良好的加速(或检查solvefor ODEProblem,它更复杂,因为它处理转换到不同的pacakges但它是相同的想法) .
在PR合并之后,可能有一个更简单的答案,例如你的小例子.
为了解决一些困惑,这里有一个声明表:
function f(x::Float64; kwargs...)
local c::Float64 # Ensures the type of `c` will be `Float64`
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = float(kwargs[:c])
else
c = 1.0
end
return x^2 + c
end
Run Code Online (Sandbox Code Playgroud)
这将强制保存的任何内容c转换为Float64或错误,从而导致类型稳定性,但不是解决方案的一般性.你使用什么形式取决于你正在做什么.
最后,还有类型断言,正如@TotalVerb所示:
function f(x::Float64; c::Float64=1.0, kwargs...)
return x^2 + c
end
Run Code Online (Sandbox Code Playgroud)
那很干净,或者你可以在函数中断言:
function f(x::Float64; kwargs...)
kwargs = Dict(kwargs)
if haskey(kwargs, :c)
c = float(kwargs[:c])::Float64
else
c = 1.0
end
return x^2 + c
end
Run Code Online (Sandbox Code Playgroud)
这将导致仅在发生断言的行上进行转换(即@TotalVerb表单不会发送,因此你不能使用另一个函数c::Int,并且它只会在首次读入关键字arg时断言(转换)) .
_f无论用户使用何种类型,第一个解决方案都将调度为类型稳定c,因此如果_f是长计算,这将获得非常优化的性能,但是对于非常快速的调用,它将具有调度开销.
第二个解决方案将解决强迫任何你设置任何类型的稳定性c是一个Float64(它会尝试转换,如果不能,错误).因此,这通过强制类型稳定性或错误来获得速度.
关键字spot(@ TotalVerb的答案)中的断言是最干净的,但以后不会自动转换(因此你可能会遇到类型不稳定.但如果你以后不小心转换它,那么你有类型稳定性,可以推断类型,因此您将获得最佳性能)并且您无法将其扩展到函数c作为其他类型(无调度)传入的情况.
最后的解决方案几乎与3相同,但不是很好.我不推荐它.如果你正在做一些复杂的断言,你可能正在设计一些错误的东西,或者真的想做一些像第一次那样的东西(在较长的函数调用中调度,类型稳定).
但请注意,版本3的发送可能会在不久的将来得到修复,这将允许您使用c::Float64和c::Int(如果需要)具有不同的功能.希望你的解决方案在这里的某个地方.