输入检查 Crystal
Type checking in Crystal
我已经问了一个相关问题 ,答案确实解决了我的问题,但我对 crystal 如何检查类型有更普遍的误解,因为我一直 运行ning 类似问题,所以如果有人可以帮助我解决这个问题,我将不胜感激。我已经尝试了很多与 Ruby 一起工作但绝对不能与 Crystal 一起工作的东西(我知道它们有很多差异,但我更熟悉 Ruby)。
这是一个class:
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 语句是否为二维数组。
但是,当 运行ning 上面的行时,我得到这个错误:
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,但仍然 运行s 通过错误的部分)。
编辑:根据第一个答案,我更改了 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
但我仍然有完全相同的错误
您遇到的问题是您使用恰好是通用 T
的实例变量间接测试 @values
类型。编译器不是那么聪明,并且有可能在运行时 @type
发生变化并且不再反映 @values
类型。即使您知道它不会,Crystal 也希望安全(否则程序会出现段错误)。 Crystal 抱怨是因为你假设了一个它不会承认的类型。
放弃 @type
。它没有帮助,而且使事情变得比他们必须的更复杂。您已经使用了泛型,现在您应该询问 @values
它是什么,然后采取相应的行动。 Crystal 会喜欢的,因为你确定类型就是这个,没有别的。
也就是说,也许你应该有 2 种不同的类型来表示 Array
和 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
我已经问了一个相关问题
这是一个class:
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 语句是否为二维数组。
但是,当 运行ning 上面的行时,我得到这个错误:
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,但仍然 运行s 通过错误的部分)。
编辑:根据第一个答案,我更改了 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
但我仍然有完全相同的错误
您遇到的问题是您使用恰好是通用 T
的实例变量间接测试 @values
类型。编译器不是那么聪明,并且有可能在运行时 @type
发生变化并且不再反映 @values
类型。即使您知道它不会,Crystal 也希望安全(否则程序会出现段错误)。 Crystal 抱怨是因为你假设了一个它不会承认的类型。
放弃 @type
。它没有帮助,而且使事情变得比他们必须的更复杂。您已经使用了泛型,现在您应该询问 @values
它是什么,然后采取相应的行动。 Crystal 会喜欢的,因为你确定类型就是这个,没有别的。
也就是说,也许你应该有 2 种不同的类型来表示 Array
和 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