Scala函数编程和隐式转换
Posted 健哥说编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala函数编程和隐式转换相关的知识,希望对你有一定的参考价值。
7、函数式编程
以下示例,都通过开发有理数为示例。以下代码与函数式编程没有啥关系:
package cn.wangjian
object Demo06_Function {
def main(args: Array[String]): Unit = {
val rational: Rational = new Rational(2, 3); //输出:2/3
val rational2: Rational = new Rational(2, 3);
val rational3: Rational = rational.add(rational2);
println(rational3);
}
class Rational(r: Int, d: Int) {
require(d != 0)
//必须要满足这个条件,否则将异常退出
private val number: Int = r;
private val denom: Int = d;
override def toString: String = number + "/" + denom;
//添加add方法
def add(that: Rational): Rational = {
new Rational(this.number * that.denom + that.number * this.denom,
this.denom * that.denom);
}
}
}
1、自引用
自引用是指this关键字,同时this关键字,又可以被省略。
//获取较大的值
def max(that: Rational): Rational ={
if(this.lessThan(that)) that else this
}
//比较
def lessThan(that: Rational): Boolean = {
//2/3 lessThan 1/2 = 2*2=4 > 1*3 所以得出2/3大于1/2
this.number * that.denom < that.number * this.denom
}
2、辅助构造方法(auxiliary-constructor)
1:可以使用this(..)定义更多的构造方法。但主构造方法,必须要被调用。
2:辅助构造方法,必须以def this(..)开始。必须先调用同一个类中的另一个构造,即必须是this(..)的形式。
声明有多个构造的类:
class Stud(n: String, a: Int) {
private var name: String = n;
//成员变量没有办法与局部变量重名了
private var age: Int = a
//构造.必须只能调用this(..)
def this(n: String) = this(n, -1)
//构造
def this(a: Int) = this("noname", a)
//自动生成的toString
override def toString = s"Stud($name, $age)"
}
实例化测试:
package cn.wangjian
object Demo07_Constructor {
def main(args: Array[String]): Unit = {
val stud: Stud = new Stud("Jack", 44);
val stud2: Stud = new Stud("Jack");
val stud3: Stud = new Stud(44);
println(stud + "," + stud2 + "," + stud3)
}
}
更多构造方法的调用过程:
1、私有字段和方法
使用private关键字,可以声明私有的成员变量和方法。默认情况下,如果没有使用任何的修饰符号,将使用public做为修饰符号。
具体代码,略。
//求两个数的最大公约数
private def gcd(a: Int, b: Int): Int = {
if (b == 0) a else gcd(b, a % b)
}
4、定义操作符号
可以通过定义操作符号将x.add(y)写成x+y,更直观。
//定义操作符号
def + (that:Rational):Rational={
add(that)
}
测试调用操作符号:
val rational4:Rational=rational+rational2;
println("使用+操作符号的:"+rational4)
5、隐式转换
用于实现更多兼容的一种代码实现。
通过定义隐式转换,就可以实现:
rational+1即加个int类型或是Long类型的功能。
package cn.wangjian
/**
* 另一种开发APP的方法
*/
object Demo05_App extends App {
//在这儿定义隐匿转换
//定义隐式转换,因为这儿要用隐匿转换,所以必须要将隐式转换放到这儿定义到Rational类中不可行
implicit def intToRational(x: Int) = new Rational(x);
//为了接收Long类型,还给Rational定义了一个接收Long类型的构造方法
implicit def longToRational(x: Long): Rational = new Rational(x)
//测试
var r1: Rational = new Rational(1, 2);
var r2: Rational = new Rational(1, 2);
var r3: Rational = r1 + r2;
var r4: Rational = r1 + 1;
var r5: Rational = r1 + 2L;
//测试
println(r3)
println(r4)
println(r5)
}
8、内建的控制结构
只人为数不多的内建控制结构:
If、while、for、try、match。
这些内建的控制结构,都有返回值,即函数式编程。
1、for..yield
for 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。Scala 中 for 循环是有返回值的。如果被循环的是 Map,返回的就是 Map,被循环的是 List,返回的就是 List,以此类推。
示例:
以下是一个普通的遍历:
scala> for(i <- 1 to 5){ println(i) }
1
2
3
4
5
以下是将i的值通过yield放入一个集合:
scala> for(i <- 1 to 5 ) yield i
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)
还可以在yield中对元素进行计算:
scala> for(i <- 1 to 10 ) yield i*2
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
scala> for(i <- 1 to 10 ) yield i%2
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 0, 1, 0, 1, 0, 1, 0, 1, 0)
使用yield遍历集合:
scala> val arr:Array[String] = Array("Jack","Mary","Rose")
arr: Array[String] = Array(Jack, Mary, Rose)
scala> for(a<-arr) yield a
res7: Array[String] = Array(Jack, Mary, Rose)
2、过虑filter
可以在for循环中,使用一个,或是多个if对数据进行过虑。
使用if条件
scala> val arr:Array[String] = Array("Jack","Mary","Rose","Alex")
arr: Array[String] = Array(Jack, Mary, Rose, Alex)
scala> for(a<-arr if a.contains("a")) yield a
res0: Array[String] = Array(Jack, Mary)
使用多个if条件
scala> for(a<-arr if a.contains("a") if a.length==3) yield a
res3: Array[String] = Array()
3、for..to
使用to关键字,两边为闭区间,to表示<=y:
scala> for(i<- 1 to 5) yield i
res4: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)
scala> for(i<- 1 to 5){
| println(i)
| }
1
2
3
4
5
4、for..until
until为开区间,不包含结束的值。以下结果,最大值为4,所以,until表示 < y。
scala> for(i<- 1 until 5) yield i
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4)
5、异常处理
1、抛出异常
Throw关键字,用于抛出异常。
def mm(n: Int): Int = {
if (n % 2 == 0)
n
else
throw new RuntimeException("不是2的倍数")
}
2、捕获异常
可以在catch中使用case处理异常,然后处理。
def ex(n: Int): Int = {
var a:Int = -1
try {
a = 100 / n;
} catch {
case ex: ArithmeticException => {
println("运算错误:" + ex.getMessage)
throw ex
}
case ex: Exception => {
println("其他错误:" + ex.getMessage)
throw ex
}
}
return a//必须要返回一个值,否则异常
}
Scala并不需要你捕获受检查的异常,也不需要你使用throws关键字,来声明异常。不过,还是可以使用@throws注解,来声明一个throws子句,来声明有可能的异常,但这并不是必须的。关于注解,以后再讲。
3、finally
与Java代码一样,finally里面包含了必须要执行的代码。
def ex(n: Int): Int = {
var a:Int = -1
try {
a = 100 / n;
} catch {
case ex: ArithmeticException => {
println("运算错误:" + ex.getMessage)
throw ex
}
case ex: Exception => {
println("其他错误:" + ex.getMessage)
throw ex
}
}finally{
println("最后必须要执行的代码...")
}
return a//必须要返回一个值,否则异常
}
6、match表达式
Scala中的match表达式,让你从若干可选项目中选择,就像是switch语句那样。
Scala中提供了比java,c更加强大的switch语句——match,而且不用担心因为忘记写break语句而发生case穿透。
scala> def say(age:Int):Int= age match{
| case 10=>10
| case 20=>20
| case 30=>30
| case _ =>100
| }
say: (age: Int)Int
scala> say(30)
res9: Int = 30
scala> say(40)
res10: Int = 100
scala> say(100)
res11: Int = 100
7、不再使用break和containue关键字
Scala中没有break和continue关键字。
用if来替换containue和用boolean来替换break。
以下示例就是用if来替换containue:
package cn.wangjian
/**
* 可以使用if语句来替换掉containue
*/
object Demo13_IfContainue {
def main(args: Array[String]): Unit = {
for(i <- 1 to 100){
if(i%2==0){
println(i);
}
}
}
}
可以使用boolean来替换break:
/**
* 用Boolean来替换掉Break
*/
object Demo14_BooleanBreak {
def main(args: Array[String]): Unit = {
var boo: Boolean = true
var i = 0;
while (i <= 100 && boo) {
i+=1
if (i >= 10) {
boo = false //设置为false以后即会停止循环
}
println(i)
}
}
}
以上是关于Scala函数编程和隐式转换的主要内容,如果未能解决你的问题,请参考以下文章