可以要求存在 Julia 命名参数吗?
Can a Julia named parameter be required to be present?
在 Ruby 中,我可以要求一个参数同时 (1) 出现,并且 (2) 有一个参数名称:
>> def f(x:)
>> x + 1
>> end
>> f()
ArgumentError: missing keyword: x
>> f(2)
ArgumentError: wrong number of arguments (given 1, expected 0)
>> f(x:7)
=> 8
也就是说,我有来传递参数,和我有来提供关联的参数名称。
我可以在Python中做同样的事情:
>>> def f(*, x):
... return x + 1
...
>>> f()
TypeError: f() missing 1 required keyword-only argument: 'x'
>>> f(3)
TypeError: f() takes 0 positional arguments but 1 was given
>>> f(x=7)
8
而且,为了更好的衡量,甚至 Swift 也可以做到这一点:
1> func f(x: Int) -> Int {return x + 1}
2> f()
error: missing argument for parameter 'x' in call
2> f(3)
error: missing argument label 'x:' in call
2> f(x:7)
$R0: Int = 8
但我不知道如何在 Julia 中执行此操作。似乎关键字参数,因为它们被称为,必须采用默认参数。这是正确的,还是有办法模拟上面的 Ruby 和 Python 示例?
这行得通吗?
function f(; x = nothing)
x + 1
end
本质上你提供了一个默认的初始值。
编辑:将默认值设置为 nothing
。
朱莉娅 0.7 和 1.x
在 Julia 0.7(这是具有所有 1.0 功能的兼容性版本)中,添加了此功能 PR #25830。
要指定一个必需的关键字参数,请在 ;
之后列出它,但不要提供默认值:
julia> f(; x) = x + 1
f (generic function with 1 method)
julia> f(;x=3)
4
julia> f()
ERROR: UndefKeywordError: keyword argument x not assigned
Julia 0.6 及更早版本
这是正确的。
在 julia 中,你不能有必需的关键字参数。
关键字参数是一种特殊类型的可选参数 -- 按名称而不是位置设置的参数。
(与此相关:您不能通过名称设置非关键字参数——您可以在 Python 和 C# 中执行此操作。)
您可以按照@amrods 的建议确保在 运行 时做到这一点。
我会用
function f(; x = nothing)
x===nothing && error("x not set.")
#...
end
如果调用者知道(推断)x
的编译类型,则该检查将被优化。
但要到 运行 时才会真正执行。
你也可以使用@Fengyang
您可以在编译时通过用生成的函数替换您的函数来强制执行此操作。但这是一个糟糕的黑客攻击。
和Ruby或Python一样可以。其实可以这么简单
julia> f(x, y; z=error()) = 1
f (generic function with 1 method)
julia> f(1, 2)
ERROR:
in f(::Int64, ::Int64) at ./REPL[65]:1
但是那个错误信息太可怕了。所以我们可以抛出更好的错误:
julia> f(x, y; z=throw(ArgumentError("z is required"))) = x + y + z
f (generic function with 1 method)
julia> f(1, 2)
ERROR: ArgumentError: z is required
in f(::Int64, ::Int64) at ./REPL[25]:1
julia> f(1, 2, z=3)
6
如oxinabox所述,错误是在运行时而不是编译时发现的,但这与Python或Ruby相同。
如果这太冗长,做一个宏很容易:
macro required(ex)
esc(Expr(:kw, ex, :(throw(ArgumentError("$($("$ex")) is required"))))
end
那你就可以了
julia> foo(x, y; @required(z), @required(w), n=4) = x + y + z + w + n
foo (generic function with 1 method)
julia> foo(1, 2)
ERROR: ArgumentError: z is required
in foo(::Int64, ::Int64) at ./REPL[59]:1
julia> foo(1, 2, z=3)
ERROR: ArgumentError: w is required
in (::#kw##foo)(::Array{Any,1}, ::#foo, ::Int64, ::Int64) at ./<missing>:0
julia> foo(1, 2, z=3, w=4)
14
julia> foo(1, 2, z=3, w=4, n=5)
15
这样做的原因是在没有传递参数时评估默认参数。通过阻止成功评估默认参数,这需要用户传递参数。
可能是由于版本漂移,这在 1.5.3
中可以正常工作。按照 Swift 示例:
julia> f(;x::Int64) = x + 1
julia> f()
ERROR: UndefKeywordError: keyword argument x not assigned
julia> f(3)
ERROR: MethodError: no method matching f(::Int64)
julia> f(x=3)
4
f(3)
案例中的错误消息可以改进。
在 Ruby 中,我可以要求一个参数同时 (1) 出现,并且 (2) 有一个参数名称:
>> def f(x:)
>> x + 1
>> end
>> f()
ArgumentError: missing keyword: x
>> f(2)
ArgumentError: wrong number of arguments (given 1, expected 0)
>> f(x:7)
=> 8
也就是说,我有来传递参数,和我有来提供关联的参数名称。
我可以在Python中做同样的事情:
>>> def f(*, x):
... return x + 1
...
>>> f()
TypeError: f() missing 1 required keyword-only argument: 'x'
>>> f(3)
TypeError: f() takes 0 positional arguments but 1 was given
>>> f(x=7)
8
而且,为了更好的衡量,甚至 Swift 也可以做到这一点:
1> func f(x: Int) -> Int {return x + 1}
2> f()
error: missing argument for parameter 'x' in call
2> f(3)
error: missing argument label 'x:' in call
2> f(x:7)
$R0: Int = 8
但我不知道如何在 Julia 中执行此操作。似乎关键字参数,因为它们被称为,必须采用默认参数。这是正确的,还是有办法模拟上面的 Ruby 和 Python 示例?
这行得通吗?
function f(; x = nothing)
x + 1
end
本质上你提供了一个默认的初始值。
编辑:将默认值设置为 nothing
。
朱莉娅 0.7 和 1.x
在 Julia 0.7(这是具有所有 1.0 功能的兼容性版本)中,添加了此功能 PR #25830。
要指定一个必需的关键字参数,请在 ;
之后列出它,但不要提供默认值:
julia> f(; x) = x + 1
f (generic function with 1 method)
julia> f(;x=3)
4
julia> f()
ERROR: UndefKeywordError: keyword argument x not assigned
Julia 0.6 及更早版本
这是正确的。 在 julia 中,你不能有必需的关键字参数。 关键字参数是一种特殊类型的可选参数 -- 按名称而不是位置设置的参数。
(与此相关:您不能通过名称设置非关键字参数——您可以在 Python 和 C# 中执行此操作。)
您可以按照@amrods 的建议确保在 运行 时做到这一点。
我会用
function f(; x = nothing)
x===nothing && error("x not set.")
#...
end
如果调用者知道(推断)x
的编译类型,则该检查将被优化。
但要到 运行 时才会真正执行。
你也可以使用@Fengyang
您可以在编译时通过用生成的函数替换您的函数来强制执行此操作。但这是一个糟糕的黑客攻击。
和Ruby或Python一样可以。其实可以这么简单
julia> f(x, y; z=error()) = 1
f (generic function with 1 method)
julia> f(1, 2)
ERROR:
in f(::Int64, ::Int64) at ./REPL[65]:1
但是那个错误信息太可怕了。所以我们可以抛出更好的错误:
julia> f(x, y; z=throw(ArgumentError("z is required"))) = x + y + z
f (generic function with 1 method)
julia> f(1, 2)
ERROR: ArgumentError: z is required
in f(::Int64, ::Int64) at ./REPL[25]:1
julia> f(1, 2, z=3)
6
如oxinabox所述,错误是在运行时而不是编译时发现的,但这与Python或Ruby相同。
如果这太冗长,做一个宏很容易:
macro required(ex)
esc(Expr(:kw, ex, :(throw(ArgumentError("$($("$ex")) is required"))))
end
那你就可以了
julia> foo(x, y; @required(z), @required(w), n=4) = x + y + z + w + n
foo (generic function with 1 method)
julia> foo(1, 2)
ERROR: ArgumentError: z is required
in foo(::Int64, ::Int64) at ./REPL[59]:1
julia> foo(1, 2, z=3)
ERROR: ArgumentError: w is required
in (::#kw##foo)(::Array{Any,1}, ::#foo, ::Int64, ::Int64) at ./<missing>:0
julia> foo(1, 2, z=3, w=4)
14
julia> foo(1, 2, z=3, w=4, n=5)
15
这样做的原因是在没有传递参数时评估默认参数。通过阻止成功评估默认参数,这需要用户传递参数。
可能是由于版本漂移,这在 1.5.3
中可以正常工作。按照 Swift 示例:
julia> f(;x::Int64) = x + 1
julia> f()
ERROR: UndefKeywordError: keyword argument x not assigned
julia> f(3)
ERROR: MethodError: no method matching f(::Int64)
julia> f(x=3)
4
f(3)
案例中的错误消息可以改进。