Можно ли написать «двойной» метод расширения? - PullRequest
0 голосов
/ 05 сентября 2018

В котлине можно написать

class A {
  fun B.foo()
}

, а затем, например, написать with (myA) { myB.foo() }.

Возможно ли вместо этого записать это как метод расширения на A? Мой вариант использования пишет

with (java.math.RoundingMode.CEILING) { 1 / 2 }

, который я хотел бы вернуть 1, суть в том, что я хочу добавить operator fun Int.div(Int) к RoundingMode.

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Это невозможно, Int уже имеет функцию div, поэтому, если вы решите написать функцию расширения div, вы не сможете применить ее, потому что функции-члены выигрывают над функциями расширения.

Вы можете написать это:

fun RoundingMode.div(x: Int, y: Int): Int {
    return if (this == RoundingMode.CEILING) {
        Math.ceil(x.toDouble() / y.toDouble()).toInt()
    } else {
        Math.floor(x.toDouble() / y.toDouble()).toInt()
    }
}

fun main(args: Array<String>) {
    with(java.math.RoundingMode.CEILING) {
        println(div(1,2))
    }
}
0 голосов
/ 06 сентября 2018

Это невозможно по нескольким причинам:

  1. В Kotlin нет понятия "функции двойного расширения"
  2. Вы не можете переопределить метод с помощью функций расширения, и оператор div уже определен в Int

Однако вы можете обойти эти проблемы с

  1. Класс контекста и расширение лямбда (например, block: ContextClass.() -> Unit)
  2. Инфиксные функции (например, используйте 15 div 4 вместо 15 / 4)

См. Пример ниже:

class RoundingContext(private val roundingMode: RoundingMode) {
    infix fun Int.div(b: Int): Int {
        val x = this.toBigDecimal()
        val y = b.toBigDecimal()

        val res = x.divide(y, roundingMode)

        return res.toInt()
    }
}

fun <T> using(roundingMode: RoundingMode, block: RoundingContext.() -> T): T {
    return with(RoundingContext(roundingMode)) {
        block()
    }
}

// Test
fun main(args: Array<String>) {
    using(RoundingMode.FLOOR) {
        println(5 div 2) // 2
    }
    val x = using(RoundingMode.CEILING) {
        10 div 3
    }
    println(x) // 4
}

Надеюсь, это поможет!

0 голосов
/ 05 сентября 2018

Нет, это невозможно. operator div должен иметь Int в качестве получателя.

Вы также не можете добавить RoundingMode в качестве приемника, поскольку может быть только однофункциональный приемник.

Однако вы можете использовать Pair<RoundingMode, Int> в качестве получателя:

operator fun Pair<RoundingMode, Int>.div(i: Int): BigDecimal =
        BigDecimal.valueOf(second.toLong()).divide(BigDecimal.valueOf(i.toLong()), first)

with(RoundingMode.CEILING) {
    println((this to 1) / 2) // => 1
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...