Вопрос о scala.math.Integral

Что делают методы mkNumericOps и mkOrderingOps scala.math.Integral и как мы можем их использовать?

Я понимаю, что функции и методы объектов могут быть объявлены implicit и использованы для неявного преобразования. Однако я не понимаю, почему объявлены методы признаков implicit.

Кстати, можно ли объявить методы класса implicit?

Ответы

Ответ 1

Во-первых, давайте посмотрим на их объявление:

implicit def mkNumericOps (lhs: T): IntegralOps
implicit def mkOrderingOps (lhs: T): Ops

Тот факт, что они являются неявными, означает их цель - предоставить некоторое автоматическое значение или преобразование. Обратите внимание, что оба они конвертируют из T в другой тип, где T - это параметр типа признака: Integral[T].

Итак, если у вас Integral[Int], то mkNumericOps даст вам автоматическое преобразование от Int до IntegralOps. Это означает, что вы сможете вызывать методы из IntegralOps или Ops на Int (или как бы то ни было это тип вашего Integral).

Теперь давайте посмотрим, что это за методы:

def % (rhs: T): T
def * (rhs: T): T
def + (rhs: T): T
def - (rhs: T): T
def / (rhs: T): T
def /% (rhs: T): (T, T)
def abs (): T
def signum (): Int
def toDouble (): Double
def toFloat (): Float
def toInt (): Int
def toLong (): Long
def unary_- (): T

Это от IntegralOps, который продолжается Ops. Интересно, что многие из них уже определены на Int! Итак, как и зачем их использовать? Вот пример:

def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
    import integral._   // get the implicits in question into scope
    list.foldLeft(integral.zero)(_ + _)
}

Итак, для любого типа T, для которого существует Integral[T] неявно доступный, вы можете передать список этого типа в sum.

Если, с другой стороны, я сделал свой метод конкретным для типа Int, я мог бы написать его без Integral. С другой стороны, я не могу написать что-то, что будет работать как для Int, так и Long и BigInt, потому что они не имеют общего предка, определяющего метод + (а тем более "нуль" ).

Приведенное выше foldLeft эффективно переводится следующим образом:

list.foldLeft(integral.zero)((x, y) => mkNumericOps(x).+(y))