Crystal 如何将 Array(T) 转换为 Array(T?)

Crystal how to convert Array(T) to Array(T?)

我正在制作 Serie - 具有缺失值的不可变时间序列。但它不能在没有空值的情况下被初始化。

class Serie(T)
  def initialize(@array = Array(T?).new); end

  def self.[](*values : T); Serie(T).new values.to_a.as(Array(T?)) end
  def self.[](*values : T?); Serie(T).new values.to_a end
end

Serie[1, nil, 2] # Works    
Serie[1, 2]      # Throws an Error

此外,它不能用没有显式类型的数组初始化并抛出错误。虽然看起来有足够的信息来推断类型。

Serie.new(Int32?)([1, nil, 2]) # Works
Serie.new([1, nil, 2])        # Throws an Error

P.S。

我正在使用 hack 来初始化它 Serie.self[...] 你知道将它初始化为类数组对象的方法吗 Serie{1, 2} 但避免添加 << 方法,因为它是静态的不可变的时间序列数据?

Array(T).new.as(Array(T?)) 无法工作,因为 Array(T?) 不是 Array(T) 的有效限制(Crystal 的泛型还不能表达协方差)。

为了从 Array(T) 转换为 Array(T?),您实际上需要创建一个类型为 Array(T?) 的新数组并将项目复制过来。一种方法是 values.map(&.as(T?)).

(从技术上讲,您还可以使用不安全类型转换来获取 Array(T?) 的实例,该实例指向与 Array(T) 相同的内存,因为二进制表示是相同的;但是通过 nilable 实例添加 nil 值时很容易中断。)这实际上不是真的,二进制表示因联合类型而不同。

I'm using a hack to initialize it with Serie.self[...] do you know a way to initialize it as Array-like object Serie{1, 2} but avoid adding << method because it's static immutable time series data?

添加 self.[] 方法可能是最好的解决方法。在 #5703.

中有关于更改类数组文字的实现以调用单个方法而不是转换为一系列 << 调用的讨论