Julia:如何将函数的参数类型定义为元组数组?

Web*_*Dev 3 julia

我有一个一维元组数组,我需要将其传递给定义为的函数

function f(a::Array{Tuple{Vararg{String}}, 1}) 
    #do some processing
end
Run Code Online (Sandbox Code Playgroud)

每个元组可以有任意数量的字符串元素,但对于数组中的所有元组,元素的数量将相同。例如,该阵列可以看起来像[("x1","x2"),("y1","y2")][("x1","x2","x3"),("y1","y2","y3")]等等。因此VARARG {字符串}的这个用法。

现在,当我运行时f([("x1","x2"),("y1","y2")]),它会引发错误

“方法错误:没有方法匹配 f(::Array{Tuple{String,String},1})”

我应该如何修改函数定义以使其有效?

hck*_*ckr 6

你得到这个MethodError是因为Tuple{Vararg{T}}它不是一个具体的类型,因为元素的数量Vararg没有指定,并且Julia 的类型参数是不变的而不是协变的

即使我们有Tuple{Vararg{String, 5}} <: Tuple{Vararg{String}},我们也没有Vector{Tuple{Vararg{String, 5}}} <: Vector{Tuple{Vararg{String}}}

julia> Tuple{Vararg{String, 5}} <: Tuple{Vararg{String}}
true

julia> Vector{Tuple{Vararg{String, 5}}} <: Vector{Tuple{Vararg{String}}}
false
Run Code Online (Sandbox Code Playgroud)

您应该改用以下签名来消除错误

function f(a::Vector{<:Tuple{Vararg{String}}})
# or
function f(a::Vector{T}) where {T <: Tuple{Vararg{String}}
Run Code Online (Sandbox Code Playgroud)

正如@crstnbr 和@Bogumi?Kami?ski 所建议的那样。这些签名将消除错误,但是,它们不限制元组的长度相同。例如,您可以调用这些函数

f([("x1, x2"), ("y1", "y2", "y3"])
Run Code Online (Sandbox Code Playgroud)

由于要确保数组中的元组包含相同数量的元素,因此需要在类型注释中指定此限制。的文档Vararg提供了有关如何指定元素数量的信息。

Vararg{T,N}

元组类型 Tuple 的最后一个参数可以是特殊类型 Vararg,它表示任意数量的尾随元素。该类型Vararg{T,N}Ntype 的元素完全对应TVararg{T}对应于零个或多个类型的元素TVararg元组类型用于表示可变参数方法接受的参数(请参阅手册中有关可变参数函数的部分。)

你可以去

function f(a::Vector{Tuple{Vararg{String, N}}}) where N 
    ...
end
Run Code Online (Sandbox Code Playgroud)

或使用紧凑的方式NTuple代替

function f(a::Vector{NTuple{N, String}}) where N

end
Run Code Online (Sandbox Code Playgroud)

这些签名将强制执行您在问题中想要的限制。


笔记

您可能过于专业化您的类型

作为@Bogumi?Kami?ski 在评论部分指出,最好使用AbstractString类型而不是具体String类型。

function f(a::Vector{<:NTuple{N, AbstractString}}) where N
...
end
Run Code Online (Sandbox Code Playgroud)

您也可以考虑使用AbstractVector代替Vector, 。

  • 这是一个很好的答案,另外一个评论是,您可能想编写一个签名,如 `g(a::Vector{T}) where {T&lt;:Tuple{Vararg{AbstractString}}}`。原因是(如答案中所述)您可能过度专业化了签名,并且通常在处理字符串时您应该接受“AbstractString”,因为在 Julia 中很容易获得“SubString”而不是“String” . (2认同)
  • 好点(我忘记了这个限制) - 我认为 - 在你写的时候,你必须把 `N` 带到外面 `where`,所以写它的最短方法可能是 `g(a::Vector {&lt;:NTuple{N, AbstractString}}) 其中 {N}`。 (2认同)