Массив <Number>: получить и установить значения Int без приведения - PullRequest
0 голосов
/ 13 мая 2018

Я строю класс Matrix и хочу иметь возможность хранить Number s в двумерном массиве.

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 с?

1 Ответ

0 голосов
/ 13 мая 2018

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

...