我想通过添加一些辅助方法为Scala中的自然数创建一个“pimp my type”。
我的第一次尝试是为Int
创建一个,为Long
创建一个(后来也可能为BigInt
创建一个)
implicit class SuperInt(n:Int) {
def square = n * n
def pow(m: Int) = math.pow(n,m)
def **(m: Int) = pow(m)
def sqrt = math.sqrt(n)
def isEven = dividesBy(2)
def isOdd = !isEven
def dividesBy(m:Int) = n % m == 0
}
implicit class SuperLong(n:Long) {
def square = n * n
def pow(m: Int) = math.pow(n,m)
def **(m: Int) = pow(m)
def sqrt = math.sqrt(n)
def isEven = dividesBy(2)
def isOdd = !isEven
def dividesBy(m:Int) = n % m == 0
}
当然完全相同的代码,不是太干,也不“感觉”正确。
所以我的问题是 - 什么是(惯用的)Scala方式一次性为Long,Int和BigInt做这个?
P.S。这是我到目前为止所尝试的,它有点工作,但我很确定它不是惯用的,并且有很多问题。
以下是关于“类型类”here的阅读结果(我仍然没有完全感觉到我100%理解)所以这就是结果(如果你的眼睛受伤了,请原谅我,我对Scala相对较新)
implicit class SuperNumber[A : Numeric](i: A) {
import Numeric.Implicits._
def squared: A = i * i
def pow(m: Int) = math.pow(i.toDouble(),m)
def **(m: Int) = pow(m)
def sqrt = math.sqrt(i.toDouble())
def isEven = dividesBy(2)
def isOdd = !isEven
def dividesBy(m:Int) = {
i match {
case n @ (_:Int | _:Long) => n.toLong() % m == 0
case other => {
val asDouble = other.toDouble()
val asLong = other.toLong()
if (asDouble == asLong) {
asLong % m == 0
} else {
false
}
}
}
}
}
(我为非Int和Long添加了“支持”,因为它似乎并不太难)
答案 0 :(得分:5)
你看起来非常接近。一些评论:
您想要的类型类是Integral
,而不是Numeric
。
不是将上下文绑定为[A: Integral]
,而是在构造函数上放置一个隐式参数,这样就可以从该对象中导入mkNumericOps
:
implicit class SuperNumber[A](i: A)(implicit integral: Integral[A]) {
import integral._