Подтвердить что ты не робот

Как реализовать универсальную математическую функцию в Scala

Я только начинаю с Scala, и что-то, что мне кажется легким, трудно понять. Я пытаюсь реализовать следующую функцию:

def square(x:Int):Int = { x * x }

Это работает отлично, но если я хочу попытаться заставить эту функцию работать для любого номера, я бы хотел сделать следующее:

def square[T <: Number](x : T):T = { x * x }

Это жалуется и говорит: error: значение * не является членом параметра типа T

Нужно ли мне реализовать для этого черту?

4b9b3361

Ответ 1

Это был один из моих первых вопросов в переполнении стека или около Scala. Проблема заключается в том, что Scala поддерживает совместимость с Java, а это означает, что его основные числовые типы эквивалентны примитивам Java.

Проблема возникает в том, что примитивы Java не являются классами и, следовательно, не имеют иерархии классов, которая допускает "числовой" супертип.

Чтобы сделать это более явным образом, Java и, следовательно, Scala, не видят общих оснований между Double + и a Int +.

Теперь путь Scala обошел это ограничение, используя Numeric и его подклассы Fractional и Integral в так называемом шаблоне типа. В основном вы используете его следующим образом:

def square[T](x: T)(implicit num: Numeric[T]): T = {
    import num._
    x * x
}

Или, если вам не нужны никакие числовые операции, но методы, которые вы вызываете, вы можете использовать синтаксис связанного с контекстом объявления типа:

def numberAndSquare[T : Numeric](x: T) = x -> square(x)

Для получения дополнительной информации см. ответы в моем собственном вопросе.

Ответ 2

Вы можете определить square как:

def square[T: Numeric](x: T): T = implicitly[Numeric[T]].times(x,x)

Этот подход имеет то преимущество, что он будет работать для любого типа T, который имеет неявное преобразование в Numeric [T] (то есть Int, Float, Double, Char, BigInt,... или любой тип, для которого вы поставлять неявное преобразование).

Edit: К сожалению, у вас возникнут проблемы, если вы попробуете что-то вроде List(1,2,3).map(square) (в частности, вы получите ошибку компиляции типа "невозможно найти неявное значение для параметра доказательства типа Numeric [T]". Чтобы избежать этой проблемы, вы может перегрузить square, чтобы вернуть функцию:

object MyMath {
   def square[T: Numeric](x: T) = implicitly[Numeric[T]].times(x,x)
   def square[T: Numeric]: T => T = square(_)
}

Надеюсь, кто-то с лучшим пониманием типа inferencer объяснит, почему это так.

В качестве альтернативы можно вызвать List(1,2,3).map(square(_)), как указал Дерек Уильямс в scala -user список рассылки.