我如何从另一个函数中将关键字参数传递给 `range` 函数,并使用 Julia 保持用户的灵活性?

How can I pass keyword arguments to the `range` function from within another function and maintain user flexibility with Julia?

我正在用 Julia 编写我的第一个模块。我有一个函数 f,它将使用向量或范围进行某些计算。我想创建一个此函数的方法,它将在继续计算之前使用 range 函数创建一个范围,以便为用户提供一些灵活性。

我写了以下内容:

# Attempt 1
function f(x,start,stop;length=1001,step=0.1)
    r=range(start,stop,length=length,step=step)
    # do more stuff with x and r
end
# error: length and step don't agree

但是,range 将只接受 steplength 之一。除非它们被一致定义,否则它不能同时采用两者。这导致我想要定义另一个函数 g,它将在 f 内部调用。 g 会调用 range 并有方法来解释三种可能的情况。

  1. 用户在调用f时指定length
  2. 用户在调用f时指定step
  3. 用户在调用 f 时既未指定 length 也未指定 step,因此使用默认值 step

我不想创建更多 f 的方法以避免过度复制 #do more stuff with x and r。我还想尽可能避免使用 if 语句,以利用多重分派并提高效率。虽然,到目前为止我还没有想出任何解决方案。

我无法使用关键字参数定义 g 的多个方法,因为关键字参数是可选的。

# Attempt 2
function g(start,stop;length=1001)
    r=range(start,stop,length=length)
end
function g(start,stop;step=0.1)
    r=range(start,stop,step=step)
end
# error: the method definitions overlap

我也无法将关键字参数转换为常规参数,因为我不知道要传递哪个参数。

# Attempt 3
function g(start,stop,length)
    r=range(start,stop,length=length)
end
function g(start,stop,step)
    r=range(start,stop,step=step)
end
function f(x,start,stop;length=1001,step=0.1)
    r=g(start,stop,y)
end
# error: no way to determine y or to differentiate length from step when passed to g

range 函数在 step/length 未指定时使用 nothing,因此以下内容应该适用于您:

function f(start, stop; step=nothing, length=nothing)
    if step === length === nothing
        step = 0.1 # default step
    end
    r = range(start, stop; step=step, length=length)
    return r
end

示例:

julia> f(1, 2; step=0.2)
1.0:0.2:2.0

julia> f(1, 2; length=3)
1.0:0.5:2.0

julia> f(1, 2) # default step
1.0:0.1:2.0

I'd rather not create more methods of f to avoid copying #do more stuff with x and r excessively

一个比较常见的模式是将核心功能移动到另一个函数,比如 _f,并有多个入口点 f,它们为 _f 构造正确的参数。这是草图:

function f(x, y)
    # construct arguments with x and y
    args = ...
    return _f(args...)
end

function f(x, y, z)
    # construct arguments with x, y and z
    args = ...
    return _f(args...)
end

function _f(args...)
    # core computation
end