Массив<Number>: получить и установить значения Int без приведения

Я строю класс Matrix и хочу иметь возможность хранить NumberS в 2-м массиве.

var data: Array<Array<Number>> = Array(width, {Array(height, {0})})

Это не работает, потому что Array<Number> а также Array<Int> инвариантны. Я могу заставить его работать, используя Array<Array<out Number>>, но Матрица будет неизменной, и я не хочу этого...

Кастинг {0 as Int} устраняет ошибку компилятора, но это не кажется хорошей идеей Я также хочу сделать такие вещи, как сложение, и я заметил, что невозможно добавить Numbers:

var n: Number = 1
n + 1 // does not work

Так как я мог решить эту проблему? И почему именно я не могу добавить два Numbers?

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 не является конкретным известным классом. Хотя может быть лучшее решение, но без знания конкретного типа. Функция расширения в основном представляет собой просто автоматическое приведение на основе типа, но не может быть единственной переменной, потому что ее необходимо определить как число, чтобы принять все типы, и так как есть две переменные, в которых оба нуждаются в правильном приведении основанный на переданном типе, это заканчивается немного грязным.

Другие вопросы по тегам