我已经问了一个相关的问题here并且答案确实解决了我的问题,但我对水晶检查的类型有一个更普遍的误解,因为我一直遇到类似的问题,所以如果有人可以帮我解决这个问题,我已经尝试了许多事情 . 与Ruby合作很好,但绝对不使用Crystal(我知道他们有很多不同,但我对Ruby更熟悉) .
这是一堂课:
class Narray(T)
getter shape
getter values
@shape : Tuple(Int32, Int32) | Nil
def initialize(values : T)
@values = values
@type = T
@shape = set_shape
end
def set_shape
if (@type == Array(Array(Int32))) || (@type == Array(Array(Float64)))
return {values.size, values[0].size} # Line causing the error
elsif (@type == Array(Int32)) || (@type == Array(Float64))
return {1, @values.size}
end
end
def is_matrix?
if @values[0].is_a?(Array(Int32)) || @values[0].is_a?(Array(Float64))
return true
else
return false
end
end
end
要定义一个数组,我应该这样做:
arr1 = Narray.new([1,2,3])
这将通过 set_shape
来检索数组的形状(表示行数和列数的元组) . 在这个方法中,我检查if语句是否是2D数组 . 但是,当运行上面的行时,我收到此错误:
in script.cr:16: undefined method 'size' for Int32
return {values.size, values[0].size}
这正是第一个if语句应该避免的 . 因为我'm initializing a 1D array, it shouldn'经过 .size
部分 .
我很确定这是一个微不足道的解释,并且有一些非常基本的东西,我没有得到,但我想得到它而不是一直绊倒这个问题 .
我怎样才能检查Crystal中的类型,因为我的方式是正确的?我已经尝试使用 is_a?
, == Type
,使用 is_matrix?
方法(它工作正常,可以确定它是2D还是1D,但仍然运行错误的部分) .
编辑:根据第一个答案,我已经改变了 set_shape
方法:
def set_shape
if (@values.is_a? Array(Array(Int32))) || (@values.is_a? Array(Array(Float64)))
return {values.size, values[0].size}
elsif (@values.is_a? Array(Int32)) || (@values.is_a? Array(Float64))
return {1, @values.size}
end
end
但我仍然有完全相同的错误
2 回答
您遇到的问题是您使用恰好是通用
T
的实例变量间接测试@values
类型 . 编译器并不那么聪明,并且在运行时可能会发生@type
更改并且不再反映@values
类型 . 即使你知道它赢了't, Crystal wants to be safe (otherwise the program segfaults). Crystal complains because you assume a type that it won't承认 .删掉
@type
. 它没有帮助,使事情变得更加复杂 . 你已经使用了泛型,现在你应该问@values
它是什么,然后采取相应的行动 . 水晶会喜欢这样,因为你确定类型将是这个而不是别的 .话虽这么说,也许你应该有2种不同的类型来表示
Array
vsArray(Array)
. 也许你的代码会更容易处理?以下代码有效: