Массив<Number>: получить и установить значения Int без приведения
Я строю класс Matrix и хочу иметь возможность хранить Number
S в 2-м массиве.
var data: Array<Array<Number>> = Array(width, {Array(height, {0})})
Это не работает, потому что Array<Number>
а также Array<Int>
инвариантны. Я могу заставить его работать, используя Array<Array<out Number>>
, но Матрица будет неизменной, и я не хочу этого...
Кастинг {0 as Int}
устраняет ошибку компилятора, но это не кажется хорошей идеей Я также хочу сделать такие вещи, как сложение, и я заметил, что невозможно добавить Number
s:
var n: Number = 1
n + 1 // does not work
Так как я мог решить эту проблему? И почему именно я не могу добавить два Number
s?
1 ответ
Число является абстрактным классом и ничего не определяет для сложения. И так как нет определенного метода для добавления чисел, вы не можете сделать numberInstane + otherNumberInstance
, Однако вы можете создать для него операторную функцию:
infix operator fun Number.plus(other: Number) : Number{
return when (this) {
is Double -> this + other.toDouble()
is Int -> this + other.toInt()
is Long -> this + other.toLong()
is Float -> this + other.toFloat()
is Short -> this + other.toShort()
is Byte -> this + other.toByte()
else -> 0
}
}
Обратите внимание, что это относится только к дополнению. Остальные функции следовали бы той же схеме, но заменяя оператор (здесь это +
) и название функции (здесь это plus
).
Как и в случае комментария mer msrd0, приведенное выше приведет к 1 + 1,5, равному 2, поскольку оно округляется. Kotlin поддерживает добавление числовых типов друг к другу, что в итоге приводит к такому ужасному решению:
infix operator fun Number.plus(other: Number) : Number{
when {
this is Double -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
this is Int -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
this is Long -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
this is Float -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
this is Short -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
this is Byte -> {
return when(other){
is Double -> this + other
is Int -> this + other
is Long -> this + other
is Float -> this + other
is Short -> this + other
is Byte -> this + other
else -> 0
}
}
else -> return 0
}
}
Вложенный оператор when помогает автоматически передавать значения, что необходимо, поскольку Number не является конкретным известным классом. Хотя может быть лучшее решение, но без знания конкретного типа. Функция расширения в основном представляет собой просто автоматическое приведение на основе типа, но не может быть единственной переменной, потому что ее необходимо определить как число, чтобы принять все типы, и так как есть две переменные, в которых оба нуждаются в правильном приведении основанный на переданном типе, это заканчивается немного грязным.