Копирование моего ответа из списка рассылки Scala, где впервые был задан вопрос:
Number
является классом Java и не имеет никакой функциональности, кроме преобразования себя в примитивные типы.К сожалению, AnyVal
в Scala не делает ничего, кроме маркировки примитивных типов, а Numeric[T]
из Scala знает только о своем собственном типе, а не о сочетании типов.
Таким образом, у вас остается довольнонеприятное сопоставление с образцом;самый короткий синтаксис, если вы уверены, что вам нужно обрабатывать только double и int, это:
list.reduceLeft((l,r) => (l: Any, r: Any) match {
case (li: Int, ri: Int) => li + ri
case _ => l.doubleValue + r.doubleValue
})
Обратите внимание, что я использую Any
, чтобы получить совпадение с шаблоном Scala для распаковки;если вы оставите его как Number, вам придется сопоставить шаблон с java.lang.Integer
, а затем valueOf
it, что является болью.
Если вы хотите больше, вам нужно будет встроить соответствующие акции:
list.reduceLeft((l,r) => (l: Any) match {
case li: Int => (r: Any) match {
case ri: Int => li + ri
case rf: Float => li + rf
case rl: Long => li + rl
case _ => li + r.doubleValue
}
case lf: Float => /* etc. */
})
Если вам нужно сделать это немного больше, вам, вероятно, лучше отказаться от Numeric
в пользу ваших собственных классов-обёрток, которые знают, как сложить себя вместе с соответствующей рекламой;затем вы можете написать сопоставление с образцом только один раз и вернуться к использованию + в своих списках.
sealed abstract class Addable {
def +(a: Addable): Addable
}
final case class MyInt(value: Int) extends Addable {
def +(a: Addable) = a match {
case MyInt(i) => MyInt(value + i)
case MyFloat(f) => MyFloat(value + f)
...
}
}
final case class MyFloat(value: Float) extends Addable {
def +(a: Addable) = a match {
case MyInt(i) => MyFloat(value + i)
...
}
}
...
Одним небольшим преимуществом этого метода является то, что вы можете решить продвигать значения не так, как стандартные (дляНапример, вы можете решить, что float + long = double, так как float действительно не вырезан, чтобы сохранить большую часть числовой точности long, и, например, выполните MyDouble(value.toDouble + f.toDouble)
.
Это все довольно неловко;Java или Scala действительно предоставляют поддержку математики смешанного типа.