Я уже задал соответствующий вопрос here, и ответ действительно исправить мою проблему, но у меня есть более общее недоразумение, как кристалл проверяет типы, так как я продолжаю сталкиваться с подобной проблемой, поэтому, если кто-то поможет мне понять это, я Будь великим. Я пробовал много вещей, которые отлично поработали с Ruby, но абсолютно не работают с Crystal (я знаю, что у них много различий, но я больше знаком с Ruby).Проверка типов в Crystal
Вот класс:
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}
Который является именно то, что первым, если утверждение следует избегать. Поскольку я инициализирую 1D-массив, он не должен проходить через часть .size
.
Я почти уверен, что это тривиальное объяснение, и что есть что-то довольно основное, что я не получил, но я хотел бы получить его, а не спотыкаться об этой проблеме все время.
Как я могу проверить тип в Crystal, так как способ, которым я пользуюсь, не так? Я пробовал использовать is_a?
, == Type
, используя метод is_matrix?
(который отлично работает и выполняет определение, является ли он 2D или 1D, но все еще проходит через неправильную часть).
EDIT: в соответствии с первым ответом, я изменил 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, но не работает (см. Мое редактирование, я добавил то, что я пробовал).Когда вы говорите, что у вас есть 2 разных типа, вы имеете в виду наличие 2 разных классов? В идеале я пытаюсь создать тип, который будет иметь те же возможности, что и numpy ndarrays, что очень удобно. И мне кажется, что часть того, почему это удобно, это потому, что это один тип для 1D/2D/Int/Float. Но я всегда открыт для предложений, и если у вас есть какие-либо «дизайнерские» советы для этого класса, было бы замечательно –
Проблема в том, что вы продолжаете ссылаться на '@ values' и не делаете локальную копию этого заранее 'values = @ values'. Тип будет ограничен правильно для локальной переменной, потому что его тип не изменится (он является локальным для функции), но переменная экземпляра может быть изменена другим потоком или другой функцией в любое время (это общее значение), поэтому его тип не будет ограничен вызовом 'is_a? 'и будет объединен. –