Scala学习笔记(一)——函数定义、匿名函数、高阶函数、柯里化、隐式参数、闭包

Scala方法和函数

函数式编程:函数是Scala的核心

方法是类的一部分,属于定义在类中的函数

定义函数

//怎么定义一个函数以及传参
object FunctionDemo01 {
  def main(args: Array[String]): Unit = {
    val i: Int = square(5)
    //    println(i)
//    printName("zhangsan")
    println(f2(2))
    println(f3(2, 2))
    println(f4(2, 2))
    println(f5(2, 2))
  }


  //定义一个函数
  def square(x: Int) = {
    println(x)
    x * x
  }

  //返回值类型为unit的函数 可以省略=
  def printName(x: String) {
    println(x)
  }


  //定义一个匿名函数
  val f1 = (x: Int) => {
    x * x
  }

  //定义一个函数2
  val f2:Int => Int=(x:Int)=>{
    x*x
  }

  //定义一个有两个参数的函数
  val f3=(x:Int,y:Int)=>{x+y}

  val f4:((Int,Int)=>Int)={(x:Int,y:Int)=>x+y}

  //不写参数名
  val f5:(Int,Int)=>Int=(_+_)
//怎么给变量赋函数
scala> def square(x: Int) = {
     |     println(x)
     |     x * x
     |   }
square: (x: Int)Int

scala> val f2=square _
f2: Int => Int = <function1>

函数调用

  1. 传值调用

    传值调用时,参数只在调用时计算一次,后续重复使用计算的结果**

    def square(x: Int): Int = { 
        println(x)    //3
        x * x             //计算3*3
    }
    square(1+2)   //先计算1+2
    
    
  2. 传名调用

    传名调用****时,参数在调用时不会计算,只有真正用到参数时才计算

    def square(x: => Int): Int = { 
        println(x)    //计算1+2
        x * x             //计算(1+2)*(1+2)
    }
    square(1+2)   //调用时不计算
    
    

案例

定义一个没有返回值的函数,实现输入一个整数,打印金字塔。例如输入10,打印如下

object function extends App {
    def readInt(x:Int)={
        for (i:Int <- 1 to x) {
          for (j: Int <- 5 - i to 0 by -1) {
            print(" ")
          }
          for (k: Int <- 1 to 2 * i - 1) {
            print("*")
          }
          println()
        }
      }

      readInt(5)
	}

命名函数

  • 通常情况下,传入参数与函数定义的参数列表一一对应
    命名参数允许使用任意顺序传入参数
def printName(first:String, last:String) = {
    println(first + " " + last)
}
 
//Prints "John Smith"
printName("John","Smith")
printName(first = "John",last = "Smith")
printName(last = "Smith",first = "John") //任意顺序

参数缺省值

  • Scala函数允许指定参数的缺省值,从而允许在调用函数时不指明该参数
def printName(first:String="John", last:String="Smith") = {
    println(first + " " + last)
}
 
//Prints "John Smith"
printName()
printName(“zhang”)
printName(“zhang”,”san”)

匿名函数

  • 指不含函数名称的函数

  • 匿名函数定义

    • “=>”左边为参数列表 (参数列表)=>{函数体}

    • “=>”右边为函数体

    • 如果函数体包括多条语句,应使用“{}”包含

      (x:Int)=>x*x
      (x:Int)=>{println(x);x*x}
      () => { System.getProperty("user.dir") }
      val f1=(x:Int)=>{println(x);x*x}  //将匿名函数赋值给变量f1
      f1(2)
      
      

高阶函数

定义

  • 高阶函数可以将其他函数作为参数或者使用函数作为输出结果
  • 常用高阶函数
    • map
    • foreach
    • filter
    • fold、foldLeft、foldRight
    • reduce
    • zip
    • flatten
    • flatMap
  1. 定义一个高阶函数:

    object HigherDemo01 {
      def main(args: Array[String]): Unit = {
    
        //定义一个普通函数
        def square(x:Int)=x*x
    
        val f0=(x:Int)=>x*x
        //定义一个高阶函数
        def dosquare(f:Int=>Int,p:Int)=f(p)
    
        //=f0(2)
        println(dosquare(f0, 2))
    
        //将一个函数作为返回值的高阶函数
        def dosquare2()={(x:Int)=>x*x}
    
        //调用一个函数作为返回值的高阶函数
        println(dosquare2()(3))
      }
        
    }
    
  2. 常用高阶函数测试——scala shell界面

    scala> val l = List(1,2,3,4,5,6,7,8,9)
    l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> l.map((_,1))
    res0: List[(Int, Int)] = List((1,1), (2,1), (3,1), (4,1), (5,1), (6,1), (7,1), (8,1), (9,1))
    
    scala> l.map(x=>x*2)
    res1: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)
    //用_变形
    scala> l.map(_*2)
    res10: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18)
    
    scala> l.foreach(println)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    scala> l.map(x=>x*2).foreach(println)
    2
    4
    6
    8
    10
    12
    14
    16
    18
    
    scala> l.filter(x=>x%2==0)
    res7: List[Int] = List(2, 4, 6, 8)
    
    scala> l.fold(0)((sum,i)=>{println(sum,i);sum+i})
    (0,1)
    (1,2)
    (3,3)
    (6,4)
    (10,5)
    (15,6)
    (21,7)
    (28,8)
    (36,9)
    res12: Int = 45
    
    scala> l.foldLeft(0)((sum,i)=>{println(sum,i);sum+i})
    (0,1)
    (1,2)
    (3,3)
    (6,4)
    (10,5)
    (15,6)
    (21,7)
    (28,8)
    (36,9)
    res13: Int = 45
    
    scala> l.foldRight(0)((sum,i)=>{println(sum,i);sum+i})
    (9,0)
    (8,9)
    (7,17)
    (6,24)
    (5,30)
    (4,35)
    (3,39)
    (2,42)
    (1,44)
    res14: Int = 45
    
    scala> l.reduce(_+_)
    res15: Int = 45
    
    scala> l.reduce((x,y)=>{println(x,y);x+y})
    (1,2)
    (3,3)
    (6,4)
    (10,5)
    (15,6)
    (21,7)
    (28,8)
    (36,9)
    res16: Int = 45
    
    scala> val list1 = List(1,2,3,4)
    list1: List[Int] = List(1, 2, 3, 4)
    
    scala> val list2 = List("a","b","c","d")
    list2: List[String] = List(a, b, c, d)
    
    scala> list1.zip(list2)
    res17: List[(Int, String)] = List((1,a), (2,b), (3,c), (4,d))
    
    scala> val list4 = List(List(1,2),List(3,4),List(5,6))
    list4: List[List[Int]] = List(List(1, 2), List(3, 4), List(5, 6))
    
    scala> list4.flatten
    res23: List[Int] = List(1, 2, 3, 4, 5, 6)
    
    scala> list4.flatMap(_.map(_*2))
    res25: List[Int] = List(2, 4, 6, 8, 10, 12)
    
    
  3. 小练习高阶函数写wordcount

    scala> val list6 = List("hello spark","hello world","hello scala","hello hadoop")
    list6: List[String] = List(hello spark, hello world, hello scala, hello hadoop)
    
    scala> list6.map(_.split(" ")).flatten
    res27: List[String] = List(hello, spark, hello, world, hello, scala, hello, hadoop)
    //同样的可以直接用flatMap
    scala> list6.flatMap(_.split(" "))
    res30: List[String] = List(hello, spark, hello, world, hello, scala, hello, hadoop)
    
    scala> list6.flatMap(_.split(" ")).map((_,1))
    res31: List[(String, Int)] = List((hello,1), (spark,1), (hello,1), (world,1), (hello,1), (scala,1), (hello,1), (hadoop,1))
    
    scala> list6.flatMap(_.split(" ")).map((_,1)).groupBy(_._1)
    res37: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(world -> List((world,1)), hadoop -> List((hadoop,1)), spark -> List((spark,1)), scala -> List((scala,1)), hello -> List((hello,1), (hello,1), (hello,1), (hello,1)))
    
    scala> list6.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size)
    res39: scala.collection.immutable.Map[String,Int] = Map(world -> 1, hadoop -> 1, spark -> 1, scala -> 1, hello -> 4)
    
    scala> list6.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size).foreach(println)
    (world,1)
    (hadoop,1)
    (spark,1)
    (scala,1)
    (hello,4)
    

中置表达式

  • 中置(缀)表达式是对只有一个参数的方法调用约定
    • 当方法只有一个参数时,可以省略“.”和“()”
//示例1
1 to 10
//实际调用
1.to(10)

//示例2
List(1,2,3).map(x=>x+1).foreach(println)
//使用中置表达式
val f=(x:Int)=>x+1
List(1,2,3) map f foreach println

函数嵌套

  • Scala函数内可以定义函数,函数内的函数也称局部函数或者内嵌函数

    举例 写个递归阶乘函数

    object Demo07 {
      def main(args: Array[String]): Unit = {
    
        //定义一个外层函数
        def factorial(i:Int):Int={
          //定义一个嵌套函数
          //5 5*4*3*2*1
          def fact(i:Int,acc:Int):Int={
            if (i<=1){
              acc
            }else{
              fact(i-1,i*acc)
              //fact(4,5*acc)
              //fact(3,4*acc)
              //fact(2,3*acc)
              //fact(1,2*acc)
              //acc
            }
          }
          fact(i,acc=1)
        }
    
        println(factorial(4))
      }
    }
    

柯里化函数

柯里化函数也叫多参数列表函数,本身就是指把接受多个参数的函数变换成接受一个单一参数 (最初函数的第一个参数 )的函数,并且返回接受余下的参数且返回结果的新函数的技术。简单理解就是改变函数的形式,不改变函数的功能。看上去有点鸡肋,但是如果和隐式参数结合使用就能 大大简化代码,同时也降低了一定的代码可读性。

  • 函数可以定义多个参数列表,当使用较少的参数列表调用多参数列表的函数时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化

    //单参数列表
    def modN(n: Int,x: Int) = ((x % n) == 0)
    //多参数列表
    def modN(n: Int)(x: Int) = ((x % n) == 0)
    //新函数接收剩余的参数列表作为其参数
    def f1(x: Int) = modN(10)(x) 
    def f2(n: Int) = modN(n)(10) 
    def f3 = modN(10)(_)  
    
    

隐式参数

  • 方法可以具有隐式参数列表,由参数列表开头的implicit 关键字标记

    • implict只能修改最尾部的参数列表,应用于其全部参数
    • Scala可自动传递正确类型的隐式值
    • 通常与柯里化函数结合使用
    object Demo09 {
      def main(args: Array[String]): Unit = {
        //定义一个隐式参数
        def sum(x:Int)(implicit y:Int)= x+y
          implicit var a=10
          println(sum(20))
      }
    }
    
    scala> val i:Int = 3.5
    <console>:11: error: type mismatch;
     found   : Double(3.5)
     required: Int
           val i:Int = 3.5
                       ^
    //定义隐式函数
    scala> implicit def doubletint(x:Double)=x.toInt
    warning: there was one feature warning; re-run with -feature for details
    doubletint: (x: Double)Int
    
    scala> val i:Int = 3.5
    i: Int = 3
    

闭包

  • 闭包是依照包含自由变量的函数字面量在运行时创建的函数值
  • 闭包是对函数本身及其所使用的自由变量的统一定义
  • 闭包的变量绑定
    • 闭包可捕获自由变量的变化
    • 闭包对捕获变量作出的改变在闭包之外也可见
	var y=1
    //定义一个闭包
    def add(x:Int) ={y=y+1;x+y}

    add(10)

    println(y)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值