Scala高阶函数与泛型

1. Scala中的函数

Scala中,函数是“头等公民”,就和数字一样。可以在变量中存放函数,即:将函数作为变量的值(值函数)

2. scala中的匿名函数,即没有函数名称的函数,匿名函数常作为高阶函数的参数使用

(x: Int) => x*3

  =>使用场景小结:

  a. 用于匿名函数中连接函数声明和函数体

  b. 用于模式匹配中,连接case条件和表达式  case "+" => "This is a positive number"

  c. 用于函数参数中,表示Call By Name的求值策略,函数实参每次在函数体内被用到时都会求值

3. scala中高阶函数分析

  高阶函数:把函数作为参数的函数

def hFunc(f: (Double) => (Double)) = f(10)
//f:为一个参数为Double,返回值也是Double的函数,作为高阶函数hFunc的参数,可以简单将f理解为函数名称的占位符,定义一个具体函数后将其替换; 

  scala> def half(x: Double):Double = x / 2
  half: (x: Double)Double

  scala> def hFunc(f: (Double) => (Double)) = f(10)
  hFunc: (f: Double => Double)Double

  scala> hFunc(half)
  res19: Double = 5.0

  //上述运行过程可看成   hFunc(half) = half(10)

4. 闭包:可理解为函数的嵌套

在一个函数定义中,包含另外一个函数的定义;并且在内函数中可以访问外函数中的变量。

5. 柯里化:

柯里化函数(Curried Function)是把具有多个参数的函数转换为一条函数链,每个节点上是单一参数。

6. scala中常用的高阶函数

scala> val numbers = List(1,2,3,4,5,6,7,8,9)
numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)      
scala> numbers.map(_*2)
res20: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)

scala> numbers.foreach(_*2)

scala> numbers
res22: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)    *******由此结果可知,map操作返回一个新的list,foreach操作只有过程无返回值 

scala> numbers.filter(_%2==0)
res23: List[Int] = List(2, 4, 6, 8)

List(1,3,7).zip(List(2,4,6))
res30: List[(Int, Int)] = List((1,2), (3,4), (7,6))

scala> numbers.partition((i:Int) => i%3==0||i%3==1)
res29: (List[Int], List[Int]) = (List(1, 3, 4, 6, 7, 9),List(2, 5, 8))scala> List(1,3,7).zip(List(2,4,6))
res30: List[(Int, Int)] = List((1,2), (3,4), (7,6))

scala> numbers.find(_%3==0)
res31: Option[Int] = Some(3)

scala> val myList = List(List(1,5,7),List(3,2,6))
myList: List[List[Int]] = List(List(1, 5, 7), List(3, 2, 6))

scala> myList.flatten
res32: List[Int] = List(1, 5, 7, 3, 2, 6)  

 flatMap与map的区别比较明显,map针对单个元素进行操作,对于嵌套的集合类型操作完成后不会压平。 

scala> val li = List(1,2,3)
li: List[Int] = List(1, 2, 3)

scala> val res = li.flatMap(x => x match {
     | case 3 => List('a','b')
     | case _ => List(x*2)
     | })
res: List[AnyVal] = List(2, 4, a, b)

scala>  li.map(x => x match {
     | case 3 => List('a','b')
     | case _ => x*2
     | })
res44: List[Any] = List(2, 4, List(a, b))

7. scala中的Option

Option[T]

在Scala里Option[T]实际上是一个容器,就像数组或是List一样,你可以把他看成是一个可能有零到一个元素的List。
当你的Option里面有东西的时候,这个List的长度是1(也就是 Some),而当你的Option里没有东西的时候,它的长度是0(也就是 None)

scala> val bag = List("1", "2", "three", "4", "one hundred seventy five")
bag: List[String] = List(1, 2, three, 4, one hundred seventy five)

scala> def toInt(in: String): Option[Int] = {
     |    try {
     |      Some(Integer.parseInt(in.trim))
     |    } catch {
     |      case e: Exception => None
     |    }
     |  }
toInt: (in: String)Option[Int]

scala> bag.map(toInt)
res46: List[Option[Int]] = List(Some(1), Some(2), None, Some(4), None)

8. scala中的泛型

  a.泛型类

  

  b. 泛型函数  

注意:这里的ClassTag是必须的,表示运行时的一些信息,比如类型。

scala>   import scala.reflect.ClassTag
import scala.reflect.ClassTag

scala>   def mkArray[T: ClassTag](elems:T*) = Array[T](elems:_*)
mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]

scala> mkArray(1,2,3,4,5)
res47: Array[Int] = Array(1, 2, 3, 4, 5)

  c.Upper Bounds Lower Bounds

  类型的上界和下界,是用来定义类型变量的范围。它们的含义如下:

  S <: T  这是类型上界的定义。也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类。

       U >: T  这是类型下界的定义。也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)

* 演示类型变量的上界: S <: T
  * S和T代表类型
  * 含义是:S必须是T的子类或者本事,则T就叫S的上界
  */

//定义父类:Vehicle代表所有的交通工具
class Vehicle{
  //方法:驾驶
  def drive()  ={println("Driving")}
}

//定义Vehicle的两个子类:Car和Bicycle
class Car extends Vehicle{
  override def drive()  ={println("Car Driving")}
}
class Bicycle extends Vehicle{
  override def drive()  ={println("Bicycle Driving")}
}
//测试
object ScalaUpperBounds {
  //定义方法
  def takeVehicle[T <: Vehicle](v:T) = {v.drive()}

  def main(args: Array[String]) {
    //定义一个交通工具的对象
    var v:Vehicle = new Vehicle
    takeVehicle(v)

    var c:Car = new Car
    takeVehicle(c)
  }
}

  d. 视图界定(View bounds 

  尽量使用视图界定,来取代泛型的上界,因为适用的范围更加广泛。视图界定<% 除了所有的子类型,还允许隐式转换过去的类型。

  隐式转换是指采用implicit关键字修饰的类函数和属性,它在定义完成后由scala在后台自动运行,当遇到匹配的转换类型,scala会自动完成隐式转换。

  

//Scala的隐式转换

//水果
class Fruit(name:String){
  def getFruitName():String = {name}
}

//猴子Monkey
class Monkey(f:Fruit){
  def say() = {println("Monkey like " + f.getFruitName())}
}

object ImplicitDemo {
  implicit  def fruitToMonkey(f:Fruit):Monkey = {new Monkey(f)}

  def main(args: Array[String]) {
    //创建一个Fruit的对象
    var f:Fruit = new Fruit("香蕉")
    //问题:能否调用f.say() 方法呢?解决方法:将Fruit的对象转换为Monkey的对象
    f.say()
  }
}

  e:协变与逆变  

  协变:Scala的类或特征的范型定义中,如果在类型参数前面加入+符号,就可以使类或特征变为协变了。泛型变量的值可以是本身类型或者其子类的类型

  逆变:在类或特征的定义中,在类型参数之前加上一个-符号,就可定义逆变范型类和特征了。泛型变量的值可以是本身类型或者其父类的类型

  

//Scala的逆变:泛型变量的值可以是本身或者其父类

package demo2{
  //父类:动物
  class Animal{}
  //子类:鸟
  class Bird extends Animal
  //麻雀
  class Sparrow extends Bird

  //吃东西的类
  class EatSomething[-T](t:T){}

  object DemoClass2 {
    def main(args: Array[String]) {
      //创建一个Bird吃东西的对象
      var c1:EatSomething[Bird] = new EatSomething[Bird](new Bird)

      //创建一个麻雀吃东西的对象
      //问题:能否将c1付给c2?
      //原因:尽管Bird是Sparrow的父类,但是EatSomething[Bird]不是EatSomething[Sparrow]的父类
      var c2:EatSomething[Sparrow] = c1
    }
  }
}
posted @ 2019-08-19 15:45  北辰Root  阅读(817)  评论(0编辑  收藏  举报