Scala函数式编程

Scala函数式编程

Scala是一门完全面向对象编程,以及完全函数式编程

**对象的本质:**对数据和行为的一个封装

**函数的本质:**函数考研当作一个值进行传递

Java和Scala不同,Java并不是完全面向对象编程语言,它含有基本数据类型,基本类型不是通过new对象的形式进行表示,这些基本数据类型要通过包装类(包装类提供了将基元转换为对象和对象转换为基元的机制)

1、函数基础

1.1 函数基本语法

def sum(x:int,y:Int):Int={
x+y}
/* def 定义函数的关键字
*	sum 函数名
*	x,y:参数名
*	Int:参数类型
*	:Int=  函数返回值类型
*	x+y 函数体
*/

函数的使用

object Function {
  def main(args:Array[String]):Unit={
    // 函数定义
      def sum(x:Int,y:Int):Int={
      x+y
    }
      //函数调用。传入两个参数10,20
    print(sum(10,20))
  }
}
// 输出 30

1.2 函数和方法的区别

函数:为了完成某一部分功能的程序语句的集合;

方法:在类中定义的函数

注意点:

  • Scala语言可以在任何的语法结构中声明任何的语法

  • 函数没有重载和重写的概念;方法可以进行重载和重写

  • Scala中函数可以嵌套定义

    object TestFunction {
     // (2)方法可以进行重载和重写,程序可以执行
     	def main(): Unit = {
     }
     def main(args: Array[String]): Unit = {
     // (1)Scala 语言可以在任何的语法结构中声明任何的语法
     import java.util.Date
     new Date()
     // (2)函数没有重载和重写的概念,程序报错
     def test(): Unit ={
     println("无参,无返回值")
     }
     test()
         
     def test(name:String):Unit={
     println()
     }
     //(3)Scala 中函数可以嵌套定义
     def test2(): Unit ={
    
     def test3(name:String):Unit={
     println("函数可以嵌套定义")
     }
     }
     }
    }
    

1.3 函数定义

函数定义的方式

  • 函数1:无参,无返回值

  • 函数2:无参,有返回值

  • 函数3:有参,无返回值

  • 函数4:有参,有返回值

  • 函数5:多参,无返回值

  • 函数6:多参,有返回值

    object Function {
      def main(args:Array[String]):Unit={
        // 函数的定义
        def add(x:Int,y:Int):Int={
          x+y
        }
          val function = new Function()
          // 使用方法,类中的函数
          print(function.add1())
          print(function.add("张三"))
        }
    
    }
    class Function{
      // 函数的定义方式
      // 无参,无返回值
      def add1(): Unit = print("这是无参,无返回值的函数")
      // 无参,有返回值
      def add():String= "这是无参,有返回值的函数"
      // 有参,无返回值
      def add1(x:Int)=print("这是有参,无返回值的函数"+"\t"+x)
      // 有参,有返回值
      def add(x:String):String=  "这是有参,有返回值的函数"+"\t"+x
      // 多参数,无返回值
      def add1(x:String,y:String)=print("这是多参数,无返回值的函数")
      // 多参数,有返回值
      def add(x:String,y:String)="这是多参数,有返回值的函数"+"\t"+x+"\t"+y
    }
    

1.4 函数参数

函数可接的参数:

(1)可变参数

(2)如果参数列表中存在多个参数,那么可变参数一般放置在最后

(3)参数默认值,一般将有默认值的参数放置在参数列表的后面

(4)带名参数

object TestFunction {
 def main(args: Array[String]): Unit = {
 // (1)可变参数
 def test( s : String* ): Unit = {
 println(s)
 }
 // 有输入参数:输出 Array
 test("Hello", "Scala")
 // 无输入参数:输出 List()
 test()
 // (2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
 def test2( name : String, s: String* ): Unit = {
 println(name + "," + s)
 }
 test2("jinlian", "dalang")
 // (3)参数默认值
 def test3( name : String, age : Int = 30 ): Unit = {
 println(s"$name, $age")
 }
 // 如果参数传递了值,那么会覆盖默认值
 test3("jinlian", 20)
 // 如果参数有默认值,在调用的时候,可以省略这个参数
 test3("dalang")
 // 一般情况下,将有默认值的参数放置在参数列表的后面
 def test4( sex : String = "男", name : String ): Unit = {
 println(s"$name, $sex")
 }
// Scala 函数中参数传递是,从左到右
 //test4("wusong") 
 //(4)带名参数
 test4(name="ximenqing")
 }
}

1.5 函数的至简原则

函数的至简原则:能省就省

至简规则如下:

(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

(2)如果函数体只有一行代码,可以省略花括号

(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

(4)如果有 return,则不能省略返回值类型,必须指定

(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用

(6)Scala 如果期望是无返回值类型,可以省略等号

(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略,变成匿名函数lambda

object Function_1 {
  def main(args: Array[String]): Unit = {
   // scala的至简原则
    // 标准形式
    def f(): Unit ={
      println("这是scala最标准的方式,无参,无返回值")
    }
    f()

    // 1、return 可以省略,Scala编译器默认把最后一行当作输出
    def f1(x:String):String={
      "scala至简原则第一条"+"\t"+x
    }
    println(f1("至简"))

    // 2、如果只有一条输出语句,可以省略大括号,数据类型可以为任意类型
    def f2():String="这是scala至简原则第二条"
    println(f2())
  }

  //  3、如果返回可以推断出来,那么可以省略 :数据类型
  def f3()={
    "这是scala至简原则第三条"
  }
  println(f3())

  //  4、如果写了return,一定要说明数据类型
  def f4():String={
    return "这是Scala至简原则第四条"
  }// 不加会报错:method f4 has return statement; needs result type

  // 5、至简原则第五条,如果返回类型是Unit,那么可以省略,跟第三点类似
  def f5(){
  println("这是Scala至简原则第五条")
  }

  // 6、至简原则第五条,如果参数是无参,在定义函数的时候加了括号,那么在调用函数的时候,括号可加可不加
  f5()
  f5  // 两个方法都可以调用

  //7、至简原则第六条,在定义函数的时候没有加括号,那么在调用函数的时候,不可以加括号
  def f6 ={
    println("至简原则第七条")
  }
  f6

  //8、如果只是追求函数的内部逻辑,并不在意函数名,可以省略def 以及函数名,但是要添加>
   def test(f:(Int,Int)=>Int):Unit ={
    val result=f(10,20)
    println(result)
  }
  def sum(x:Int,y:Int): Int ={
    x+y
  }
  // 一种方法  test(sum)
  // 另外一种方法
  test((x:Int,y:Int)=>{x+y})
}

1.6 函数即对象

Scala是一门完全面向对象的编程语言,即Scala面向对象

Scala同样是一门函数式编程的编程语言,即Scala面向函数

1.6.1 函数对象

将函数对象作为变量使用

/*
* 在java中,创建一个对象是使用User user=new User()
* 在Scala中 使用 val f=test _ 即可以表示
* 此时f可以通过编译器自动推断类型,函数对象的类型称之为函数类型Function0[Unit]
* 这里类型中的0:表示函数参数列表中参数的个数  Unit:表示函数没有返回值
*/

val f=test _
//如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给变量
var f()=>Unit=test
val f:Function0[Unit]=test _
// 两个的效果是一样的,若有参数,需要将参数进行指定,以及返回值进行指定
  def sum(x:Int,y:Int): Int ={
    x+y
  }
// 将函数对象赋值给一个变量,那么这个变量其实就是函数,变量可以传参后执行  f()
  val f:Function2[Int,Int,Int]=sum _
  println(f)
// Function_1$$$Lambda$6/2096171631@7e0babb1

注意:

  • 函数对象的参数最多只能22个

  • 函数对象和函数的不同:函数的参数个数没有个数,但是把函数当作对象进行使用的时候,函数对象的参数只能22个

1.6.2 函数对象的参数

将函数对象作为参数使用

/*
*	java的引用
*	public void test(User user){
*	user.xxx()''	}
*	User user=new User();
*	test(user)
*/
def fun():Unit=println("test...")
// test函数的参数是一个函数对象
def test(f:()=>Unit):Unit={
    f()
}
// 将函数对象赋值为一个变量
val f=fun _
// 这个变量(函数对象)传入到另外一个函数中
test(f)
1.6.3 函数对象的返回值

可以将函数对象作为返回值进行输出

// 函数的返回类型一般下都不声明,使用自动推断
def outer():Uint={
	def inner():Unit={
	print("inner.....")
	}
	inner _
}
// 使用,此时,f就是函数对象,有函数类型,()=>Unit
val out=outer()
// 调用函数
f()
// 函数编程的写法·1
outer()()

1.7 lambda至简原则

1、下划线的省略

​ 1)将函数名称直接作为参数传递给另外一个函数,不需要使用下划线

​ 2)使用下划线的目的是不让函数执行,而是将它作为对象使用,那么如果能明确函数不执行,那么可以不加下划线

def fun():Unit=print("test...")
// 这两种方法都可以执行
val f=fun _
val f:()=>Unit =fun


object Function_lambda {
  // 调用函数对象,这个f需要传两个int值  x,y
  // 并返回一个int值  z
  // int值 z 将作为test的参数进行执行,返回值为Unit
  def main(string: Array[String]): Unit = {
    def test(f: (Int, Int) => Int): Unit = {
      val result = f(10, 20)
      println(result)
    }

    def sum(x: Int, y: Int): Int = {
      x + y
    }

    //test(sum) 不使用这种方法

    // 如果函数没有名称和def,那么是匿名函数,一般就是作为参数使用
    // 这样可以减少sum这个函数的使用,不在意函数名,更在意函数内部结构
    test(
      (x: Int, y: Int) => {
        x + y
      }
    )

    // 匿名函数作为参数使用时,可以采用【至简原则】
    // 是指函数在使用过程中进行一个至简

    //1、匿名函数的逻辑只有一行代码,那么大括号可以省略
    test(
      (x: Int, y: Int) => x + y
    )

    //2、匿名函数的参数类型如果可以推断出来,那么参数类型可以省略
    test(
      (x, y) => x + y
    )

    //  3、匿名函数中如果参数列表的个数只有一个,那么小括号可以省略
    def fun(f: (String) => Unit): Unit = {
      f("zhangsan")
    }

    def test1(name: String): Unit = {
      println(name)
    }
    // 匿名函数第一步
    fun(
      (name) => {
        println(name)
      }
    )
    // 匿名函数第二步
    // 如果只有一行代码可以1)省略大括号,2)参数可以省略,3)小括号可以省略,4)参数只是用一次,可以使用下划线代替
    fun(println(_))

    //  4、匿名函数中如果参数按照顺序只执行一次的场合,那么可以使用下划线代替参数,省略参数列表
    test(
      _ + _
    )

  }
}

1.8 闭包与柯里化

1.8.1 闭包

如果一个函数使用了外部的变量,但是改变这个变量的生命周期;将这个变量包含到当前函数的作用域,形成闭合的效果(环境),这个环境称之为闭包环境,简称闭包

def outer(x:Int):={
	def inner(y:Int):Unit={
	print("inner.....")
	}
	inner _
}
val inner=outer(10)
val result=inner(20)
println(result)
// 这个函数在代码上可以行得通,但是在逻辑上行不通,因为在逻辑上当一个函数执行完之后,就会收回那个函数中定义的变量,无法使用到另外一个函数里面

闭包的场景

1、内部函数是用来外部的数据,改变数据的声明周期

2、将函数作为对象使用,改变函数本身的生命周期

3、所有匿名函数都有闭包

4、内部函数返回到外部使用也会有闭包

1.8.2 柯里化

在函数传递参数的时候,参数之间并没有关系,那么如果在传值的时候,同时传递,会存在耦合性,而且增加了函数的执行复杂性,必须所有参数都执行完成,函数才可以执行完成。

柯里化:就是为了将函数简单化,将无关的参数进行分离,可以设定多个参数列表

// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存在闭包
 def f3(a:Int)(b:Int)={
 a + b
 }
 println(f3(10)(3))
 }

1.9 递归函数

一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用

  // 函数递归
  def digui(x:Int):Int={
 // 阶乘
 // 递归算法
 // 1) 方法调用自身
 // 2) 方法必须要有跳出的逻辑
 // 3) 方法调用自身时,传递的参数应该有规律
 // 4) scala 中的递归必须声明函数返回值类型

    if (x==1)
       x
    else
      x*digui(x-1)
  }
  val result=digui(5)
  println("递归的结果是"+result)

注意

Java的栈内存是有大小限制的。方法执行时,压栈的内存也是有大小的,那么栈内存不可能无限压栈;如果压栈的此时超过阈值,就会出现错误,即使有跳出的逻辑也会出错。

Scala采用了一种特殊的语法优化递归操作**:尾(伪)递归**。Scal采用while循环实现尾递归;java中尾递归没有优化

// 这样将递归函数放在尾部去执行,就可以实现尾递归的效果
def test():Unit={
println("test...")
test()
}
test()

1.10 惰性函数

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

def main(args: Array[String]): Unit = {
 lazy val res = sum(10, 30)
 println("----------------")
 println("res=" + res)
}
def sum(n1: Int, n2: Int): Int = {
 println("sum 被执行。。。")
 return n1 + n2
}
输出结果:
----------------
sum 被执行。。。

res=40

注意:lazy 不能修饰 var 类型的变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值