我正在尝试了解有关 Julia 类型系统如何工作的更多细节。
考虑以下简单示例
julia> v = [1]
1-element Vector{Int64}:
1
julia> typeof(v)
Vector{Int64} (alias for Array{Int64, 1})
julia> vany::Vector{Any} = v
1-element Vector{Int64}:
1
julia> typeof(vany)
Vector{Any} (alias for Array{Any, 1})
我很想知道发生了什么(如果有的话)使
vany
与 v
不同?
这似乎是一个简单的问题,但我相信它实际上是相当微妙的。
让我们考虑几点:
v
。我认为我的猜测是正确的,Julia 已经检查了该表达式右侧的对象,并得出结论,它分配给 v
的类型是包含所有整数元素的 Vector
。默认情况下,使用 Int64
类型表示整数。因此 Julia 得出结论,v
必须引用 Vector{Int64}
。v
一定是某个分配的对象,它引用向量元素所在的内存块。我不确定这个v
是否存在于堆的堆栈上。它引用的data
是动态长度向量,必须存在于堆上。我还认为 Julia 必须在引用中添加一些类型信息。这样它就知道
v
引用了 Vector{Int64}
。但我对此并不完全确定。将这个问题改写为
v
?
可能是合理的考虑以下代码行时,事情会变得更加复杂。
vany::Vector{Any} = v
这里到底发生了什么?
v
Int64
转换为
Any
?
这是否意味着向量的每个元素现在都是一个具有额外间接级别的对象? (这意味着每个元素都是一个
Any
Julia 如何知道
vany
Vector{Any}
而不是
Vector{Int64}
?该类型信息保存在哪里?
julia> typeof(v[1])
Int64
julia> typeof(vany[1])
Int64
看起来两个向量的元素仍然是
Int64
。
我不确定这是否意味着:
要么:两个向量在内存中的表示是相同的,这意味着转换为
::Vector{Any}
vany
上设置一些元数据,以便它认为它是
::Vector{Any}
而不是
Vector{Int64}
或:
vany
Any
内,但是函数调用
typeof
遵循装箱内容以找出在本例中它包含
Int64
[1]
是
Vector
的构造函数,其参数都是
Int64
。因此,
[1]
会产生
Vector{Int64}
。
Julia 中对象的内存表示有些复杂(因为实现高性能需要很大的自由度),但 TLDR 是
Vector{Int}
是一个装箱对象,这意味着它分配有类型标签。类型标签有 2 个字,告诉运行时变量的类型是什么以及保存一些用于 GC 的元数据。类型有一个布局,而 Vector{Int}
的布局意味着
Int
是内联存储的(从技术上讲,因为
Vector
是可调整大小的,所以还有另一个重定向,并且
Vector
拥有固定大小的
Memory
,但那是一个很多细节在这里并不重要)。v 的元素是否单独从 Int64 转换为 Any?
是一个抽象类型。值不能具有类型不。
Any
Any
。这里发生的是构造一个新的
Vector{Any}
并将
v
中的元素复制到
vany
。Julia 如何知道 vany 引用的是 Vector{Any} 而不是 Vector{Int64}?该类型信息保存在哪里?
类型标签
这是否意味着向量的每个元素现在都是一个具有额外间接级别的对象?
的布局是一个盒子数组。是的。
Vector{Any}