Scala函数式编程

本文详细阐述了Scala中函数与方法的区别与联系,包括定义、使用、类型转换等内容,并介绍了函数式编程的重要概念如闭包和Currying函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

函数(function) vs 方法(method)

  • 函数

    • 函数定义使用:=>, 如val f1 = (x:Int) => x+3
    • f1的类型是Int=>Int,也即是个函数,输入是Int,返回是Int类型的函数
    • 函数是一个完整的对象,和普通对象一样,有属于的类型,如Function1<T,T>(描述有一个输入参数,返回的是T),有方法,如apply
      • apply方法包含了函数的body部分代码,当调用函数变量名(args)时,scala实际会转换为调用函数对象的apply(args)方法
    • 函数可以赋值给变量和作为参数
    • 函数既然是对象,消耗的内存比method多
    • 常见函数形式

      //f1函数参数是x,类型Int,自动推断返回类型是Int
      val f1 = (x:Int) => x+3 
      //REPL显示,冒号右边是类型,f1: Int => Int = <function1>
      var f1 = => 100 //函数必须有参数列表,该例报错
      var f2 = () => 100 //函数可以有一个空的参数列表
    • 有一种说法是将函数叫做无名方法,匿名方法
      //匿名函数赋值给变量,最后一行如果是表达式,可以作为返回值
      val sayHelloFunc = (name: String) => println("Hello, " + name) 
  • 方法

    • 方法定义使用:def,如def m1(x:Int) = x+3,参数是x,类型Int,返回类型是Int(自动推断)
    • 常用方法形式

      def m2 = 100;//方法可以没有参数列表
      
      def m3() = 100 //方法可以有一个空的参数列表
      
      def m4(x:Int,Y:Int) = {100} //多个参数,默认最后一行表达式是返回值,在REPL中显示m4: (x: Int, Y: Int)Int,说明是方法
      
      //方法参数可以是函数
      m1(x: => Int) //函数名是x,该函数无输入,返回Int
      m1(x: Int => Int) //参数是函数,函数名是x,该函数输入是Int,返回Int,冒号右边是类型,带=>是函数类型
      
      //方法调用:无参数列表或空参数列表的方法,方法名就可以触发调用
      m2 //m2是无参列表
      m3 //m3是空参数列表
      
      //方法可以转换为函数
      val f3:(Int)=>Int = m4 //期望出现函数的地方,会自动转为函数,f3冒号后(Int)=>Int说明f3是函数类型,方法m4自动转为函数
      val v3 = m4 //不期望出现函数的地方,方法并不会自动转换成函数,报错
      val v3 = m4 _ //强制将方法转为函数,这种情况需要加`空格和_`
      
      //参数传递可以默认按值传递,如果参数类型是函数,则按名传递
      def m_call_2(x: => Int)=List(x,x) //两次进行x方法或函数调用
      def m_p(y:Int)=4
      def m_t(x: (Int) => Int)={
        println(x) //<function1> 说明x是一个函数,因为带参方法是不能直接使用的
        println(x(1)) //4 调用了函数;但如果这里x是无参,直接使用x,不是输出函数形式,而是调用了,说明x是方法,所以比较疑惑
      }
      m_t(m_p)
      
      //疑问
      def m_val()=3
      def m_t(x: => Int)={ //我理解这里参数类型是函数,但解释说这个传名参数x是一个方法,不是函数,不知道为啥
        val y = x _ //强制将传名方法转为函数
        println(y)  //<function0>
        println(x) //3,为什么不是function呢,因为x是一个无名方法参数,所以可以通过名字x来调用
        println(x) //3,为什么不是function呢,因为x是一个无名方法参数,所以可以通过名字x来调用
      }
      m_t(m_val) //如果参数类型是方法,方法也可以这么传递参数,解释不通   
      
      //方法调用其他形式
      缀操作符:op obj 被解释称obj.op
      中缀操作符:obj1 op obj2被解释称obj1.op(obj2)
      后缀操作符:obj op被解释称obj.op
    • 方法其他补充:

      • 构成:方法名、参数、返回类型、方法体
      • def sayHello(name: String, age: Int): Unit = {}

      如果带参数,参数的类型必须给出
      如果需要返回值,需要符号=;与Java不同,可用return也可以不用return返回值;类型可以自动推断,但如果最后一行调用自身,则无法推断
      Unit类似java void,无返回,这种函数叫过程(procedures)

    • 支持默认参数,如def sayHello(name: String, age: Int=29)
    • 支持混合使用未带值参数和带值参数,注意未带值数必须在带值
      参数前面
    • 变长参数:参数个数不定
      def sum(nums: Int*) = {}
      普通调用方式sum(1, 2, 3, 4, 5)
      序列调用方式sum(1 to 5: _*)

    • 按名传递

      def getFirst(x: Int, y: =>Int) = {
        x
      }
      def loop:Int = loop //可以将looploop,很奇怪,返回类型Int,函数体是loop
      getFirst(loop, 3) //死循环,函数体里会触发loop
      getFirst(3, loop) //不会死循环,loop按名传递,使用的时候才触发
高阶函数:以下不区分函数和方法
  • 接收其他函数作为参数的函数或者返回值是函数
//接收函数作为参数
def greeting(func: (String) => Unit, name: String) { func(name) } 

//使用
greeting((name: String) => println("Hello, " + name), "leo")

//高阶函数可以自动推断出参数类型,而不需要写明类型
greeting((name) => println("Hello, " + name), "leo")

//对于只有一个参数的函数,可以省掉小括号
greeting(name => println("Hello, " + name), "leo")

//通过通配符_,可以省略输入参数,_个数代表参数的个数
greeting(println(_), "leo")
Array(1, 2, 3, 4, 5).map(2 * _)
(1 to 9).map("*" * _).foreach(println _)
(1 to 20).filter(_ % 2 == 0)
//reduceLeft: 从左侧元素开始,进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,依次类推
(1 to 9).reduceLeft( _ * _) //多个参数再调用的时候依次填入
Array(3, 2, 5, 4, 10, 1).sortWith(_ < _) 

//返回值为函数
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name) 
闭包
  • 函数在变量不处于其有效作用域时,还能够对变量进行访问,即为闭包
/* 闭包就是拥有对外部函数或类的变量的引用,
从而可以在外面函数栈执行结束以后,依然握有外面函数栈/堆变量的引用
,并可以改变他们的值。
*/
def main(args: Array[String]) {
  var factor = 3

  def multiplier(i:Int) = {
    i * factor
  }
/* 我理解是调用multiplier(2)的时候,会进行栈的切换,
导致局部变量factor看不见了,而闭包却可以看见,还能修改外部变量
*/
  println(multiplier(2))
}
Currying函数
  • 简单说,通过返回函数可以将原来一次接收多个参数的一个函数,转换为多个函数多次调用参数的情况;在函数部分重用,定义的时候简便
//带有两个括号定义的函数叫currying函数
def sum3(a: Int)(b: Int) = a + b
//调用方式
sum2(1)(1)
//类似以下定义
def sum2(a: Int) = (b: Int) => a + b //sum2: (a: Int)Int => Int,参数是a,返回类型是函数
def sum(a: Int, b: Int) = a + b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值