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、内建的控制结构

只人为数不多的内建控制结构:

Ifwhilefortrymatch

这些内建的控制结构,都有返回值,即函数式编程。

 

1for..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()

 

3for..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

 

4for..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子句,来声明有可能的异常,但这并不是必须的。关于注解,以后再讲。

3finally

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//必须要返回一个值,否则异常
}

 

 

 

 

 

6match表达式

Scala中的match表达式,让你从若干可选项目中选择,就像是switch语句那样。

Scala中提供了比javac更加强大的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、不再使用breakcontainue关键字

Scala中没有breakcontinue关键字。

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函数编程和隐式转换的主要内容,如果未能解决你的问题,请参考以下文章

15Scala隐式转换和隐式参数

scala学习笔记-隐式转换与隐式参数(18)

2021年大数据常用语言Scala(三十八):scala高级用法 隐式转换和隐式参数

Scala 学习笔记之隐式参数和隐式转换并用

Scala基础高阶函数隐式转换AKKA编程

Scala基础:隐式转换与隐式参数