Как наследовать операторы в Kotlin? - PullRequest
0 голосов
/ 19 июня 2020

У меня есть два следующих класса:

class Volume(var value: Double, unit: Unit) {
    var unit: Unit = unit
        private set

    enum class Unit(symbol: String){
        MILLILITER("ml"),
        CENTILITER("cl"),
        DECILITER("dl"),
        LITER("l"),
        TEASPOON("tsp"),
        TABLESPOON("tbsp"),
        FLUIDOUNCE("floz"),
        SHOT("jig"),
        GILL("gi"),
        CUP("cup"),
        PINT("pt"),
        QUART("qt"),
        GALLON("gal")
    }
}

class Mass(var value: Double, unit: Unit) {
    var unit: Unit = unit
    private set

    enum class Unit(symbol: String){
        GRAM("g"),
        DECAGRAM("dag"),
        HECTOGRAM("hg"),
        KILOGRAM("kg"),
        OUNCE("oz"),
        POUND("lb")
    }
}

Я хочу создать операторы для обоих классов для базовых операций c arithmeti c, например:

operator fun inc(): Mass {
    value++
    return this
}

Поскольку оба класса будут иметь одинаковую логику операторов, я не хочу дублировать эту часть кода.

Моя первая идея заключалась в том, что оба класса наследуются от интерфейса PhysicalQuantity, который содержит операторы. В этом случае следующий код не работает, потому что IDE ожидает IPhysicalQuantity в качестве возвращаемого типа, но имеет тип Volume:

interface IPhysicalQuantity() {

    var value: Double
    var unit: IUnit

    operator fun inc(): IPhysicalQuantity {
        value++
        return this
    }
}

fun main() {
    var vol = Volume(10.0, Volume.Unit.CENTILITER)
    vol++
}

Та же проблема с абстрактным суперклассом.

1 Ответ

0 голосов
/ 19 июня 2020

Проблема с выполнением этого внутри интерфейса IPhysicalQuantity заключается в том, что вы не хотите возвращать объект как тип интерфейса IPhysicalQuantity из метода inc. Вместо этого вы хотите сохранить его исходный тип (Volume или Mass), поэтому вам придется использовать там универсальные шаблоны. Однако я не нашел способа сделать это без сложного синтаксиса и непроверенного приведения:

interface IPhysicalQuantity<T : IPhysicalQuantity<T>> {
    var value: Double

    operator fun inc(): T {
        value++
        return this as T
    }
}

class Volume(override var value: Double, unit: Unit): IPhysicalQuantity<Volume>

Однако вы можете сделать это довольно просто с расширением, не делая сам интерфейс универсальным c, если у вас работает:

operator fun <T : IPhysicalQuantity> T.inc(): T {
    value++
    return this
}
...