利用Scala的隐式转换,扩展对象方法


Int对象是没有判断当前数是不是质数的方法的,所以一般都是直接写在方法里去判断,或者抽离成方法去调用,举个例子

原始方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 //1-100内的质数
import util.control.Breaks._
object NumberTest {
def printEven() = {
for (i <- 0 to 100) {
breakable {
i match {
case i if i < 1 => break
case 1 | 2 | 3 => print(i + ",")
case i if (canNotExcept(i)) => print(i + ",")
case _ => break
}
}
}
}

def canNotExcept(i: Int): Boolean = {
val half = i / 2
var flag = true
breakable {
for (n <- 2 to half) {
if (0 == i % n) {
flag = false
break
}
}
}
flag
}
}

隐式转换转换方式

如果想让Int直接带有判断质数的能力,基本不太可能
但是如果换一种思路:把Int转换成一个能判断自己是不是质数的类型,就好了啊

转换类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
implicit class IntUtil(i: Int) {
// 判断数字为质数
def isPrime: Boolean = {
i match {
case i if 1 > i => false
case 1 | 2 | 3 => true
case i => {
val half = i / 2
if (except(half)) false else true
}
}

}

// 判断数字不是质数
def isNotPrime: Boolean = !isPrime

//尾递归,判断能佛被比divisor小的数整除
@tailrec
final def except(divisor: Int): Boolean = {
if (2 == divisor ) 0 == i % divisor
else if (0 == i % divisor) true
else except(divisor - 1)
}
}

使用更方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import util.control.Breaks._
// 引入自定义的隐式转换
import com.zing.my.IntUtil._

object NumberTest {
def printEven() = {

for (i <- 0 to 100) {
breakable {
// i 会直接隐式转换成IntUtil类型,然后就可以使用isNotPrime方法了
if (i.isNotPrime) {
break
}
print(i + ",")
}
}
}
}

小结

大佬说,尾递归是函数式编程的精髓之一,而隐式转换是Scala的精髓之一。我玩Scala大约一周了,暂时的体会是用起来真爽,看起来真难懂。
本文展示了使用隐式类型,帮助扩展原有类的方法,虽然实质上是把原有类型转换成新类型,但是写起来看着就是方法被扩展了。

优点是:

  • 可以更加方便的对类型进行扩充,不限于方法,也可以是属性,方法参数等
  • 合适情况下可读性也更强,更加专注于逻辑而不是实现细节

缺点是:

  • IDEA无法自动帮你导入隐式函数或者类,只能自己手工来
  • 不合适的情况下大佬隐藏了细节,导致初学者完全不知道为什么直接就调用到了方法。不知> 道实现的逻辑

隐式转换的原理其实就是编译器发现编译不能直接进行,再尝试你导入的隐式转换,转换成功了就编译成转换后的结果,不成功,那就真的不成功了。

工具书:《Scala编程 第三版》

喜欢请点个赞
转载请注明出处:https://www.jianshu.com/u/4915ed24d1e3
如有错误,请务必指正。谢谢
我的博客:https://xzing.github.io/