Scala的高级特性

 

 高阶函数

概念

Scala混合了面向对象和函数式的特性,咱们一般将能够做为参数传递到方法中的表达式叫作函数。在函数式编程语言中,函数是“头等公民”,高阶函数包含:做为值的函数、匿名函数、闭包、柯里化等等。java

做为值的函数   

能够像任何其余数据类型同样被传递和操做的函数,每当你想要给算法传入具体动做时这个特性就会变得很是有用。算法

 

 

定义函数时格式:val 变量名 (输入参数类型和个数)  =>  函数实现和返回值类型编程

=”表示将函数赋给一个变量闭包

=>”左面表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型编程语言

匿名函数

在Scala中,你不须要给每个函数命名,没有将函数赋给变量的函数叫作匿名函数。函数式编程

 

 

因为Scala能够自动推断出参数的类型,全部能够写的跟精简一些函数

 

 

还记得神奇的下划线吗?这才是终极方式spa

 

 

柯里化

什么是柯里化

柯里化(Currying)指的是把原来接受多个参数的函数变换成接受一个参数的函数过程,而且返回接受余下的参数且返回结果为一个新函数的技术。scala

 

 

 

例子

(1)     一个普通的非柯里化的函数定义,实现一个加法函数:3d

 

scala> def plainOldSum(x:Int,y:Int)=x+y
plainOldSum: (x: Int, y: Int)Int
 
scala> plainOldSum(1,2)
res0: Int = 3

 


(2)     使用“柯里化”技术来定义这个加法函数,原来函数使用一个参数列表,“柯里化”,把函数定义为多个参数列表: 

scala> def curriedSum(x:Int)(y:Int)=x+y
curriedSum: (x: Int)(y: Int)Int
 
scala> curriedSum(1)(2)
res1: Int = 3
 
当你调用curriedSum (1)(2)时,其实是依次调用两个普通函数(非柯里化函数),
第一次调用使用一个参数x,返回一个函数类型的值,
第二次使用参数y调用这个函数类型的值。

 


(3)     使用下面两个分开的定义在模拟curriedSum柯里化函数: 

首先定义第一个函数:
scala> def first(x:Int)=(y:Int)=>x+y
first: (x: Int)Int => Int
 
而后咱们使用参数1调用这个函数来生成第二个函数:
scala> val second =first(1)
second: Int => Int = <function1>
scala> second(2)
res2: Int = 3

 


(4)     使用curriedSum 来定义second 

 

scala> val onePlus=curriedSum(1)_
onePlus: Int => Int = <function1>

 
下划线“_” 做为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。
 
scala> onePlus(2)
res3: Int = 3

调用生成的函数,给函数传入参数,便可获得咱们想要的结果。

 

  

总结

scala柯里化风格的使用能够简化主函数的复杂度,提升主函数的自闭性,提升功能上的可扩张性、灵活性。能够编写出更加抽象,功能化和高效的函数式代码。

闭包

什么是闭包

闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包一般来说能够简单的认为是能够访问不在当前做用域范围内的一个函数。

例子

package cn.itcast.closure

/**
  * scala中的闭包
  * 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
  */
object ClosureDemo {

  def main(args: Array[String]): Unit = {
       val y=10

      //变量y不处于其有效做用域时,函数还可以对变量进行访问
        val add=(x:Int)=>{
          x+y
        }

    //在add中有两个变量:x和y。其中的一个x是函数的形式参数,
    //在add方法被调用时,x被赋予一个新的值。
    // 然而,y不是形式参数,而是自由变量
    println(add(5)) // 结果15
  }
}

 

 

隐式转换和隐式参数

隐式转换

Scala提供的隐式转换和隐式参数功能,是很是有特点的功能。是Java等编程语言所没有的功能。它能够容许你手动指定,将某种类型的对象转换成其余类型的对象或者是给一个类增长方法。经过这些功能,能够实现很是强大、特殊的功能。

Scala的隐式转换,其实最核心的就是定义隐式转换方法,即implicit conversion function。定义的隐式转换方法,只要在编写的程序内引入,就会被Scala自动使用。Scala会根据隐式转换方法的签名,在程序中使用到隐式转换方法接收的参数类型定义的对象时,会自动将其传入隐式转换方法,转换为另一种类型的对象并返回。这就是“隐式转换”。其中全部的隐式值和隐式方法必须放到object中

然而使用Scala的隐式转换是有必定的限制的,总结以下:

  • implicit关键字只能用来修饰方法、变量(参数)。
  • 隐式转换的方法在当前范围内才有效。若是隐式转换不在当前范围内定义(好比定义在另外一个类中或包含在某个对象中),那么必须经过import语句将其导。

隐式参数

所谓的隐式参数,指的是在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的参数,即隐式值,并注入参数。

Scala会在两个范围内查找:

  • 当前做用域内可见的val或var定义的隐式变量;
  • 一种是隐式参数类型的伴生对象内的隐式值;

 

 

隐式转换方法做用域与导入

(1)Scala默认会使用两种隐式转换,一种是源类型或者目标类型的伴生对象内的隐式转换方法;一种是当前程序做用域内的能够用惟一标识符表示的隐式转换方法。

(2)若是隐式转换方法不在上述两种状况下的话,那么就必须手动使用import语法引入某个包下的隐式转换方法,好比import test._。一般建议,仅仅在须要进行隐式转换的地方,用import导入隐式转换方法,这样能够缩小隐式转换方法的做用域,避免不须要的隐式转换。

隐式转换的时机

(1)当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换

(2)当方法中的参数的类型与目标类型不一致时

 

隐式转换和隐式参数案例

隐式转换案例一

(让File类具有RichFile类中的read方法)

package cn.itcast.implic_demo

import java.io.File
import scala.io.Source

object MyPredef{
  //定义隐式转换方法
  implicit def file2RichFile(file: File)=new RichFile(file)
}

class RichFile(val f:File) {
  def read()=Source.fromFile(f).mkString
}

object RichFile{
  def main(args: Array[String]) {
    val f=new File("E://words.txt")

    //使用import导入隐式转换方法
    import MyPredef._
    //经过隐式转换,让File类具有了RichFile类中的方法
    val content=f.read()
    println(content)
  }
}

 

 

隐式转换案例二

(超人变身)

package cn.itcast.implic_demo

class Man(val name:String)
class SuperMan(val name: String) {
  def heat=print("超人打怪兽")
}

object SuperMan{
  //隐式转换方法
  implicit def man2SuperMan(man:Man)=new SuperMan(man.name)
  def main(args: Array[String]) {
      val hero=new Man("hero")

      //Man具有了SuperMan的方法
      hero.heat
  }
}

 

隐式转换案例三

(一个类隐式转换成具备相同方法的多个类)

package cn.itcast.implic_demo

class A(c:C) {
    def readBook(): Unit ={
      println("A说:好书好书...")
    }
}
class B(c:C){
  def readBook(): Unit ={
    println("B说:看不懂...")
  }
  def writeBook(): Unit ={
    println("B说:不会写...")
  }
}
class C
object AB{
  //建立一个类的2个类的隐式转换
  implicit def C2A(c:C)=new A(c)
  implicit def C2B(c:C)=new B(c)
}

object B{
  def main(args: Array[String]) {
    //导包
    //1. import AB._ 会将AB类下的全部隐式转换导进来
    //2. import AB._C2A 只导入C类到A类的的隐式转换方法
    //3. import AB._C2B 只导入C类到B类的的隐式转换方法
    import AB._
    val c=new C
    //因为A类与B类中都有readBook(),只能导入其中一个,不然调用共同方法时代码报错
    //c.readBook()
    //C类能够执行B类中的writeBook()
    c.writeBook()
  }
}

 



隐式参数案例四

(员工领取薪水)

package cn.itcast.implic_demo

object Company{
  //在object中定义隐式值    注意:同一类型的隐式值只容许出现一次,不然会报错
  implicit  val aaa="zhangsan"
  implicit  val bbb=10000.00
}

class Boss {
  //注意参数匹配的类型   它须要的是String类型的隐式值
  def callName()(implicit name:String):String={
    name+" is coming !"
  }

  //定义一个用implicit修饰的参数
  //注意参数匹配的类型    它须要的是Double类型的隐式值
  def getMoney()(implicit money:Double):String={
   " 当月薪水:"+money
  }
}

object Boss extends App{
  //使用import导入定义好的隐式值,注意:必须先加载不然会报错
  import Company._
  val boss =new Boss
  println(boss.callName()+boss.getMoney())
}
相关文章
相关标签/搜索