函数参数中的 Julia 类型参数 Nesting/Scope
Julia Type Parameters Nesting/Scope in Function Parameters
继 之后,我试图了解函数方法中类型参数范围的详细信息。
例如:
f(x::Vector{<:Number}) = sum(x)
g(x::Vector{T}) where T<:Number = sum(x)
<:Number
约束仅涵盖 f
:
的参数列表
julia> methods(f)
f(x::Array{#s1,1} where #s1<:Number)
但是好像g
被它参数化了:
julia> methods(g)
g(x::Array{T,1}) where T<:Number
"[y]ou generally want T
to cover as little of the signature as possible" aside from style 和限制 T
的范围有什么原因吗?
在性能、调度或代码生成方面是否有任何影响?
f
和 g
语法相同,所以没有区别。
确实,上面的 f
和 g
与 Michael 所指出的是等价的。您可以通过编写动态检查它:
julia> f(x::Vector{<:Number}) = sum(x)
f (generic function with 1 method)
julia> f(x::Vector{T}) where T<:Number = sum(x)
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f":
[1] f(x::Array{T,1}) where T<:Number in Main at REPL[2]:1
并且 Julia 告诉您方法定义被覆盖了(因此它被认为是等效的)。
但是,一般来说,范围界定确实很重要。看这个例子:
julia> f(::Vector{Vector{<:Real}}) = "inner"
f (generic function with 1 method)
julia> f(::Vector{Vector{T}}) where {T<:Real}= "outer"
f (generic function with 2 methods)
julia> f(::Any) = "all else"
f (generic function with 3 methods)
julia> methods(f)
# 3 methods for generic function "f":
[1] f(::Array{Array{#s1,1} where #s1<:Real,1}) in Main at REPL[1]:1
[2] f(::Array{Array{T,1},1}) where T<:Real in Main at REPL[2]:1
[3] f(::Any) in Main at REPL[3]:1
julia> f([[1]])
"outer"
julia> f(Vector{<:Real}[[1]])
"inner"
julia> f([Any[1]])
"all else"
关于正常(即类型稳定)代码中的性能,Julia 执行静态方法分派,所以这应该无关紧要。也许你可以设计一个人为的例子,需要复杂的动态方法分派或动态代码生成,这可能很重要(但出于实际原因,这不应该是相关的 - 只需使用代表你需要的规范)。
继
例如:
f(x::Vector{<:Number}) = sum(x)
g(x::Vector{T}) where T<:Number = sum(x)
<:Number
约束仅涵盖 f
:
julia> methods(f)
f(x::Array{#s1,1} where #s1<:Number)
但是好像g
被它参数化了:
julia> methods(g)
g(x::Array{T,1}) where T<:Number
"[y]ou generally want T
to cover as little of the signature as possible" aside from style 和限制 T
的范围有什么原因吗?
在性能、调度或代码生成方面是否有任何影响?
f
和 g
语法相同,所以没有区别。
确实,上面的 f
和 g
与 Michael 所指出的是等价的。您可以通过编写动态检查它:
julia> f(x::Vector{<:Number}) = sum(x)
f (generic function with 1 method)
julia> f(x::Vector{T}) where T<:Number = sum(x)
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f":
[1] f(x::Array{T,1}) where T<:Number in Main at REPL[2]:1
并且 Julia 告诉您方法定义被覆盖了(因此它被认为是等效的)。
但是,一般来说,范围界定确实很重要。看这个例子:
julia> f(::Vector{Vector{<:Real}}) = "inner"
f (generic function with 1 method)
julia> f(::Vector{Vector{T}}) where {T<:Real}= "outer"
f (generic function with 2 methods)
julia> f(::Any) = "all else"
f (generic function with 3 methods)
julia> methods(f)
# 3 methods for generic function "f":
[1] f(::Array{Array{#s1,1} where #s1<:Real,1}) in Main at REPL[1]:1
[2] f(::Array{Array{T,1},1}) where T<:Real in Main at REPL[2]:1
[3] f(::Any) in Main at REPL[3]:1
julia> f([[1]])
"outer"
julia> f(Vector{<:Real}[[1]])
"inner"
julia> f([Any[1]])
"all else"
关于正常(即类型稳定)代码中的性能,Julia 执行静态方法分派,所以这应该无关紧要。也许你可以设计一个人为的例子,需要复杂的动态方法分派或动态代码生成,这可能很重要(但出于实际原因,这不应该是相关的 - 只需使用代表你需要的规范)。