型水晶
检查我已经问一个相关的问题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语句应该避免什么第一。由于我正在初始化一维数组,它不应该通过.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
但我还是有相同的错误
你的问题是,你间接测试@values
键入,使用恰巧是通用的实例变量T
。编译器不是那么聪明,并且在运行时有可能会更改@type
并且不再反映@values
类型。即使你知道它不会,水晶想要安全(否则程序段错误)。水晶抱怨,因为你承担一个它不会承认的类型。
删除@type
。这不是帮助,而是让事情比他们必须更复杂。你已经使用了一个通用的,现在你应该问@values
它是什么,然后采取相应的行动。水晶会喜欢这样,因为你确定这种类型将是这个,而不是别的。
话虽这么说,也许你应该有2种不同类型的表示Array
VS Array(Array)
。也许你的代码会更容易处理?
下面的代码工作:
class Narray(T)
getter shape
getter values
@shape : Tuple(Int32, Int32) | Nil
def initialize(@values : T)
@shape = set_shape
end
def set_shape
values = @values # => asign to local var
if values.is_a?(Array(Array(Int32))) || values.is_a?(Array(Array(Float64)))
return {values.size, values[0].size}
elsif (T == Array(Int32)) || (T == 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, 4]])
pp arr1.set_shape # => {2,2}
pp arr1.is_matrix? # => true
谢谢您的回答。我已经尝试了你的建议,即直接评估@values的类型,但没有起作用(请参阅我的编辑,我已经添加了我尝试过的)。当你说有两种不同的类型时,你的意思是有两个不同的类?理想情况下,我试图创建一个类型与numpy ndarrays相同的功能,非常方便。在我看来,为什么它很方便的一部分是因为它是1D/2D/Int/Float的一种类型。但我总是对建议开放,如果你对这个类有任何“设计”建议,它会很棒 –
问题在于你一直提到'@ values'并且不提前制作它的本地副本'values = @ values'。该类型将被正确限制为一个局部变量,因为它的类型不会改变(它是本地的函数),但实例变量可能随时被另一个线程或另一个函数改变(它是一个共享值),所以它的类型类型不会受到'is_a?'调用的限制,并保持为联合。 –