英文:
Idiomatic way to get the container type instead of element type in Julia?
问题
我想要实现以下的行为。
container_type(::Type{Vector{T}}) where T = Vector
container_type(::Type{Matrix{T}}) where T = Matrix
当然,我不希望硬编码每个具体类型。首先,我想要能够以编程方式为AbstractVector
的每个子类型执行此操作。我尝试了以下方法。
container_type(::Type{V{T}}) where {V <: AbstractVector, T} = V
但是,这会导致TypeError
,因为类型变量不能嵌套。我的下一个猜测是遍历AbstractVector
的所有子类型。以下方法适用于AbstractVector
子类型的有限子集。
for vec_type in nameof.(subtypes(AbstractVector))
try
@eval begin
container_type(::Type{$(vec_type){T}}) where T = $(vec_type)
end
catch
for (exc, bt) in current_exceptions()
showerror(stderr, exc, bt)
end
end
end
需要try
-catch
块,因为subtypes(AbstractVector)
中的某些类型由模块作用域。
nameof
函数会丢弃模块名称,这就是为什么它们在@eval
块中无法找到的原因。
我目前被困在这一点。如何解决这个错误?在这里是否有更好的方法?
英文:
I want to implement the following behavior.
container_type(::Type{Vector{T}}) where T = Vector
container_type(::Type{Matrix{T}}) where T = Matrix
But, of course I do not want to hard-code every concrete type. For starters, I want to be able to programmatically do this for every subtype of AbstractVector
. I tried the following.
container_type(::Type{V{T}}) where {V <: AbstractVector, T} = V
But, this results in a TypeError
because type variables cannot be nested. My next guess is iterating over all the subtypes of AbstractVector
. The following works for a limited subset of the subtypes of AbstractVector
for vec_type in nameof.(subtypes(AbstractVector))
try
@eval begin
container_type(::Type{$(vec_type){T}}) where T = $(vec_type)
end
catch
for (exc, bt) in current_exceptions()
showerror(stderr, exc, bt)
end
end
end
The try
-catch
block is required because some of the types in subtypes(AbstractVector)
are scoped by modules.
julia> subtypes(AbstractVector)
20-element Vector{Any}:
AbstractRange
Base.ExceptionStack
Base.LogicalIndex
Base.MethodList
Base.ReinterpretArray{T, 1, S} where {T, S}
Base.ReshapedArray{T, 1} where T
BitVector (alias for BitArray{1})
CartesianIndices{1, R} where R<:Tuple{OrdinalRange{Int64, Int64}}
Core.Compiler.AbstractRange
Core.Compiler.BitArray{1}
Core.Compiler.ExceptionStack
Core.Compiler.LinearIndices{1, R} where R<:Tuple{Core.Compiler.AbstractUnitRange{Int64}}
Core.Compiler.MethodList
DenseVector (alias for DenseArray{T, 1} where T)
LinearIndices{1, R} where R<:Tuple{AbstractUnitRange{Int64}}
PermutedDimsArray{T, 1} where T
AbstractSparseVector (alias for SparseArrays.AbstractSparseArray{Tv, Ti, 1} where {Tv, Ti})
SubArray{T, 1} where T
Tables.EmptyVector
Test.GenericArray{T, 1} where T
and nameof
discards the module names altogether
julia> subtypes(AbstractVector) .|> nameof
20-element Vector{Symbol}:
:AbstractRange
:ExceptionStack
:LogicalIndex
:MethodList
:ReinterpretArray
:ReshapedArray
:BitArray
:CartesianIndices
:AbstractRange
:BitArray
:ExceptionStack
:LinearIndices
:MethodList
:DenseArray
:LinearIndices
:PermutedDimsArray
:AbstractSparseArray
:SubArray
:EmptyVector
:GenericArray
which is why they cannot be found in the @eval
block.
I have been stuck at this point. How can I work around this error? Is there any other approach that might work better here?
答案1
得分: 1
Here's the translation of the code part you provided:
也许你想要:
ctype(::T) where T <: AbstractArray = T.name.wrapper
现在你可以这样做:
julia> ctype(1:4)
UnitRange
julia> ctype([7, 8, 9])
Array
请注意,Vector
和 Matrix
是 Array
的别名,而不是类型(具有不同维度参数的别名),因此,如果你想区分它们,你需要直接获取类型。
ctype2(::T) where T <: AbstractVector = T
请注意,这是代码的翻译部分,没有其他内容。
英文:
Perhaps you want:
ctype(::T) where T <:AbstractArray = T.name.wrapper
Now you can do:
julia> ctype(1:4)
UnitRange
julia> ctype([7,8,9])
Array
Note that Vector
and Matrix
are aliases to Array
rather than types (aliases with different dimension parameters) so if you want to distinguish between the two you need to get the type directly.
ctype2(::T) where T <:AbstractVector = T
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论