在 Scala 中,类(class)的定义比 Java 面相对象的类定义要简洁一些,因为 Scala 在类定义时就同时定义了该类的主构造器(primary constructor)。我们知道,构造函数只不过是一种特殊的函数(或称为方法)而已,所以 Scala 中的类定义个人觉得跟方法、函数定义的格式看起来差不多。
所谓的函数式对象,其实就是指对象内部没有可变的状态,即类里面的字段都是用关键字 val(value的意思)定义的。
借助《Programming in Scala》中的例子,我们定义一个有理数(Rational)类,在此我们将有理数表示为分数的形式,即1 / 2、3 / 5的格式。其要求如下:
1、 该类的对象(即任意有理数)能够相互之间进行一些基本运算,如加、减、乘、除,此外,还应该能与正数进行这些运算;
2、 确保构造出有理数(Rationla 对象)时不能出现分母为零的情况;
3、 重写 toString()方法,以最简分数的格式打印出 Rational 对象;
4、 可以只给定一个分子来构造有理数,此时我们默认分母为 1,于是需要重载(overload)构造函数,Scala 中称为从构造器。
看一下实现代码:
1. // 有理数类
2. class Rational(n: Int, d: Int){
3.
4. //在构造对象时确保分母不为零
5. require(d != 0)
6.
7. // 获得分子分母的最大公约数
8. private val g = gcd(n.abs, d.abs)
9. val numer: Int = n / g // 分子
10. val denom: Int = d / g // 分母
11.
12. // 重载构造器,此时的有理数实为整数
13. def this(n: Int) = this(n, 1)
14.
15. // 重写toString,必须加上override关键字
16. override def toString = {
17. if(denom == 1)
18. numer.toString
19. else
20. numer + "/" + denom
21. }
22.
23. // 常见的add方法
24. def add(that: Rational) :Rational = {
25. new Rational(
26. numer * that.denom + that.numer * denom,
27. denom * that.denom
28. )
29. }
30.
31. // 操作符形式的加法
32. def +(that: Rational): Rational ={
33. new Rational(
34. numer * that.denom + that.numer * denom,
35. denom * that.denom
36. )
37. }
38.
39. def *(that: Rational): Rational ={
40. new Rational(
41. numer * that.numer,
42. denom * that.denom
43. )
44. }
45.
46. def -(that: Rational): Rational ={
47. new Rational(
48. numer * that.denom - that.numer * denom,
49. denom * that.denom
50. )
51. }
52.
53. def /(that: Rational): Rational ={
54. new Rational(
55. numer * that.denom,
56. that.numer * denom
57. )
58. }
59.
60. // 求倒数的前缀操作符,必须加上unary_修饰~
61. def unary_~(that: Rational): Rational ={
62. new Rational(
63. denom, numer
64. )
65. }
66.
67. // 递归求分子分母的最大公约数,必须指明结果类型
68. private def gcd(a: Int, b: Int): Int =
69. if(b == 0) a else gcd(b, a % b)
70.
71. // 有理数的比较:小于
72. def lessThan(that: Rational) =
73. numer * that.denom < that.numer * denom
74.
75. // 求两数中的较大数
76. def max(that: Rational) : Rational =
77. //if(lessThan(that)) that else this //省略this也可以
78. if( this lessThan that ) that else this
79. }
说明一下代码中的几点,也便于我自己理清Scala 中的编程规范:
1、 require(d != 0) 是Scala 中的方法、主构造器要求调用发必须满足的先决条件,是一种限制,确保了程序的正常运行。看起来功能类似于断言机制,但是 Scala 中也有断言啊,所以我目前还不明白这两者的区别所在。
2、 私有的 gcd() 函数是递归函数,必须指明其结果类型(返回类型),它用于求得分子、分母的最大公约数,用于对分数的化简。此外,在 Scala 中,尾递归函数可以被 Scala 编译器进行优化,尽量写尾递归的函数,这才是 Scala 函数式编程偏向的以递归替代while循环的基础。
3、 Scala 中的构造器重载使用了 this 关键字,其实是从构造器委托了主构造器的实现。
4、 add()方法和加号 + 都实现了 Rational 对象(有理数)的加法运算,看起来像是 C++ 中的运算符重载。其实,在 Scala 中并没有操作符的概念,就算是 1 + 2 中的加号,也是一个由Int类型的 1 所调用的函数而已。(说起来,Scala 更像是完全的面向对象语言,至少比 Java 中还存在原始类型要好)当然,我们还可以完整地定义出其他减法sub 函数等等。
5、 对于求倒数操作符 ~ ,因为在这里我们将它作为一个前缀操作符,所以必须用 unary_ 修饰,告诉编译器将 ~ 看作前缀操作符。
有了上面一系列的函数定义(上面的代码中多是操作符定义),我们就能够进行编写一些脚本代码来测试一下 Rational 类的这些运算了,如下:
1. val a = new Rational(1, 3)
2. val b = new Rational(1, 2)
3.
4. println(a add b)
5. println(a.add(b))
6.
7. println(a.lessThan(b))
8. println(a lessThan b)
9.
10. println(a.max(b))
11. println(a max b)
12.
13. val c = new Rational(3)
14. println(c)
15.
16. println(new Rational(66, 42))
17.
18. print("1/3 + 1/2 = ")
19. println(a + b)
20.
21. print("1/3 - 1/2 = ")
22. println(a - b)
23.
24. print("1/3 * 1/2 = ")
25. println(a * b)
26.
27. print("(1/3) / (1/2) = ")
28. println(a / b)
由于我把上面 Rational 类的定义和这一些针对 Rational 类测试的代码放在同一个 .scala 脚本文件中,并且 Rational 类的代码中有许多中文的注释,所以在使用 scala 命令执行这脚本时需要用选项 –encoding 指定字符集 UTF-8 ,运行结果如下:
本文转自 xxxx66yyyy 51CTO博客,原文链接:http://blog.51cto.com/haolloyin/384387,如需转载请自行联系原作者