Как реализовать универсальную математическую функцию в Scala - PullRequest
29 голосов
/ 30 октября 2010

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

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

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

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

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

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

Ответы [ 2 ]

32 голосов
/ 30 октября 2010

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

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

Проще говоря, Java и, следовательно, Scala не видят никаких общих оснований между Double s + и a * 1009.* 's +.

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

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

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

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

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

10 голосов
/ 30 октября 2010

Вы можете определить 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(_)
}

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...