Julia中Union{Nothing,String}与Union{Nothing,Bool}矩阵初始化报错问题
Julia中带Nothing的Union类型数组初始化及赋值报错原因解析
核心原因:数组内存布局差异
Julia中数组的undef初始化行为完全由元素类型的内存布局决定:
- 当数组元素类型是全isbits类型的Union:
Nothing和Bool都属于不可变、无需GC追踪的isbits值类型,因此Union{Nothing,Bool}属于isbits Union。这类数组的元素直接inline存储在数组的内存块中,使用undef初始化时,Julia会自动将类型标记设为Union的第一个成员的默认值,因此你得到的数组所有元素都是nothing,不存在未定义引用。 - 当数组元素类型的Union包含非isbits类型:
String是引用类型,不属于isbits类型,因此Union{Nothing,String}和Union{Nothing,Bool,String}都不属于isbits Union。这类数组的元素是指向堆内存的指针,undef初始化只会分配指针数组的存储空间,不会给指针指向的内容赋值,因此所有未手动赋值的元素都是#undef(未定义引用)。
你可以单独给Union{Nothing,String}类型的矩阵的指定位置赋值字符串且正常生效,是因为直接赋值操作只会覆盖对应位置的指针,不需要读取该位置原本的#undef值,因此不会触发错误。只有当你需要读取#undef位置的值的时候才会报错,比如遍历数组、整体赋值、打印未赋值的元素等操作都会触发读取,从而抛出UndefRefError。
赋值报错的具体原因
你构造的三类型大矩阵Array{Union{Nothing, Bool, String}}(undef,10,5)属于引用存储类型,未手动赋值的位置都是#undef:
- 赋值给
Union{Nothing,Bool}类型矩阵时操作正常,说明你操作的前5行元素都已经被手动赋值为Nothing或Bool类型,不存在未定义引用,读取这些元素不会触发错误。 - 赋值给
Union{Nothing,String}类型矩阵时抛出UndefRefError,说明你读取的源矩阵对应位置存在未赋值的#undef元素,访问这些元素时直接触发了未定义引用错误,和类型转换无关。
解决方案
如果需要所有数组初始化后默认值为nothing,不要使用undef初始化,改用主动填充的方式:
# 初始化全nothing的Union{Nothing,String} 5×5矩阵 mat = fill(nothing, Union{Nothing,String}, 5, 5) # 或者先生成undef数组再填充 mat = Array{Union{Nothing,String},2}(undef,5,5) fill!(mat, nothing)
这样初始化的数组所有元素都是合法的nothing值,不会出现#undef,后续赋值和访问都不会触发未定义引用错误。
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

