在Julia中,isimmutable函数可以告诉您对象何时是不可变的。但是,它不适用于类型,所以我想为类型编写一个版本。根据我在其他地方找到的建议,一个很好的开端是:
isimmtype(t::Type) = error("Type $t has not defined isimmtype")
isimmtype(t::DataType) = begin
if !t.isconcretetype
error("Abstract types are neither immutable nor mutable")
else
return !t.mutable
end
end这是有用的,并回答了许多但不是所有类型的问题。这些失败可分为两类,我到目前为止已经注意到了:
这个模式起作用的
Union和UnionAll类型。两者似乎都有简单的解决办法。在UnionAll的情况下,我们可以使用类型变量的上限对类型的具体化进行测试。对于一个Union{A,B},我们可以比较A和B类型的可变性,并推导出联合的可变性。我继续写了这些解决方案,我认为这是一个合理的类似特性的语法,它部分地奏效了:
"""
Mutability
The Mutability type is an abstract trait type with children Mutable, Immutable,
and UnknownMutability.
"""
abstract type Mutability end
struct Mutable <: Mutability end
struct Immutable <: Mutability end
struct UnknownMutability <: Mutability end
const MUT_TYPE = Mutable()
const IMM_TYPE = Immutable()
const UNK_TYPE = UnknownMutability()
"""
mutability(obj)
Yields an object of type Mutable, Immutable, or UnknownMutability depending on
whether the given type object is mutable, immutable, or unknown.
"""
mutability(T::Type) = UNK_TYPE
isimmtype(T::Type) = IMM_TYPE === mutability(T)
mutability(T::DataType) = begin
if !T.isconcretetype
return UNK_TYPE
elseif T.mutable
return MUT_TYPE
else
return IMM_TYPE
end
end
mutability(::Core.TypeofBottom) = UNK_TYPE
mutability(T::UnionAll) = mutability(T{T.var.ub})
mutability(::Type{String}) = IMM_TYPE
mutability(::Type{Symbol}) = IMM_TYPE
# This one causes problems:
mutability(::Type{Union{A,B}}) where {A,B} = begin
let mA=mutability(A), mB=mutability(B)
if mA === UNK_TYPE || mB === UNK_TYPE || mA !== mB
return UNK_TYPE
else
return mA
end
end
end如果定义了所有这些方法(最后一个方法),那么mutability函数就会像我预期的那样工作,除了Union{A,B}类型的一个例外,这些类型总是被标记为未知。但是,如果定义了最后一个方法,那么它将匹配像Int64这样的类型,而在函数体中甚至没有绑定B (即在方法的开头添加println(A, B)会导致由于未定义B而导致的错误)。我可以看到,在这个A <: Union{A,B}中有一个模糊的地方,但是如何显式地匹配关于Union类型的查询?在这种情况下,如何防止Type{Union{A,B}}在Type{A}上匹配?
另外:还有其他情况是mutability函数标签错误吗?
发布于 2019-10-13 15:59:08
在发布这个问题之后,我意识到一个可能的答案是在默认方法中显式测试Union类型:
mutability(T::Type) = begin
if typeof(T) !== Union
return UNK_TYPE
else
let mA=mutability(T.a), mB=mutability(T.b)
if mA === UNK_TYPE || mB === UNK_TYPE || mA !== mB
return UNK_TYPE
else
return mA
end
end
end
end使用上面的其他方法,这将正确地得到以下所有测试:
map(k->k=>(mutability(k), isimmtype(k)),
[String, Symbol, Int64,
Dict{Int64,String}, Array, Array{Int64,1},
Tuple, Tuple{}, Tuple{Int64,String,Symbol},
Union{String,Symbol}, Union{String,Array}, Union{Array,Dict}])12-元素数组{Pair,1}:# String => (Immutable(),true) # Symbol => (Immutable(), true) # Int64 => (Immutable(), true) # Dict{Int64,String} => (Mutable(), false) # Array => (Mutable(), false) # Array{Int64,1} => (Mutable(), false) # Tuple => (UnknownMutability(), false) # Tuple{} => (Immutable(), true) # Tuple{Int64,String,Symbol} => (Immutable(), true) # Union{String, Symbol} => (Immutable(), true) # Union{String, Array} => (UnknownMutability(), false) # Union{Dict, Array} => (Mutable(), false) #
在我看来这一切都是正确的。但是,我仍然想知道是否有其他在Union上显式匹配的解决方案,以及是否存在这些函数无法正确检测可变性的其他实例!
发布于 2020-02-05 05:57:16
只要您不关心struct类型需要isimmtype(::Type{TheStructType})的显式定义,这是可行的:
isimmtype(x::Type) = throw(ErrorException("isimmtype($x) is not defined"))
function isimmtype(::Type{T}) where {T}
if !T.isconcretetype
throw(DomainError("Abstract types are neither immutable nor mutable"))
else
return !T.mutable
end
end
isimmtype(::Type{Symbol}) = true
isimmtype(::Type{String}) = true
function isimmtype(x::Union)
return all(isimmtype, Base.uniontypes(x))
end
isimmtype(x::UnionAll) = isimmtype(x{x.var.ub}) https://stackoverflow.com/questions/58364817
复制相似问题