Вопрос о scala.math.Integral - PullRequest
       24

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

3 голосов
/ 01 апреля 2011

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

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

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

1 Ответ

8 голосов
/ 01 апреля 2011

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

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))
...