scala之函数进阶

版权声明: https://blog.csdn.net/weixin_39966065/article/details/90173656

目录

一:scala的函数

0.函数之于 java/scala地位

1.scala中的函数

2.匿名函数

3.高阶函数

(1)将函数当成参数进行传递

(2)将函数作为返回值

(3)是否有其它方式将函数变为返回值

(4)匿名函数作为返回值的作用

4.高阶函数的类型判断

5.常用的高阶函数

6.闭包

7.SAM转换:待续

8.Currying 函数(函数柯里化)

9.scala中带名函数return的使用

10.Lambda表达式

二:重点的创建规则汇总

1.匿名函数的创建

2.把函数当参数书进行传递  

3.把函数传递给变量


一:scala的函数

0.函数之于 java/scala地位

特点:
    函数与类、对象一样,都是一等公民
    现在只是一门语言,应用于数据分析领域(更加卓著)
    
Java的生态:
   重要的框架和系统太多: 
   Spring:大型项目
   Lucene:给项目加上索引
   Activiti:工作流的系统   
   Hadoop:大数据

1.scala中的函数

定义:与java中的函数必须依托于某个类而言。在scala中它可以独立定义,独立存在。

将函数赋值给变量的固定写法:
必须在 ”函数名称“ 后面加上 “空格”和“下划线” ,不带 “()”

例子:
def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _

怎么通过被赋予值的变量去使用函数?作用?
直接传递函数的名称是否可行?? 

例子:
sayHelloFunc("leo")

能否使用 var 变量类型进行接收
例子:
def sayHello(name: String) { println("Hello, " + name) }
var sayHelloFunc = sayHello _   
//可行 


2.匿名函数

(1)语法规则:(函数名: 参数类型) => {方法体}
(2)作用:1>将函数赋予值给某个变量
                         2>直接将匿名函数传入到其它函数

例子:      
val sayHelloFunc = (name: String) => println("Hello, " + name)
sayHelloFunc("Tom")
//输出:Hello,Tom 

(3)特性:函数名称直接当成变量去使用

例子2:
def sayHelloFunc(name:String)=println("Hello, "+name)
def greeting(func:(String)=>Unit,name:String)=func(name)
val sayHelloFunc2 = sayHelloFunc _

scala> greeting(sayHelloFunc,"leo")
scala> greeting(sayHelloFunc2,"leo")
//Hello, leo


3.高阶函数


(1)将函数当成参数进行传递


1>以函数作为传入参数的函数的书写规范:
func:(String)=>Unit 
函数变量名称 + “:" + "(传参类型)" + “返回值类型” 

例子: 
val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func:(String) => Unit,name:String){ func(name)}
greeting(sayHelloFunc, "leo")

java事例:
public Class SayHello{
 public abstract sayHello();
}

public void greeting(String name,new SayHello(){
  public void sayHello(String name){System.out.println("Hello, "+name)}
})
{
    sayHello.sayHello(name)
}

好处:对比Java,它的代码更加的简洁

2>
例子2:
Array的高阶函数
Array(1, 2, 3, 4, 5).map((num: Int) => num * num)
 

(2)将函数作为返回值

1.规则:只能直接定义一个匿名函数
2.构造方式:
def 函数名称(传参)=(传入参数)=>{方法体}

注意:必须用 “=” 等号连接
例子:
def getGreetingFunc(msg:String)=(name:String)=>{println(msg+","+name)} 
创建结果:getGreetingFunc: (msg: String)String => Unit
val greetingFunc = getGreetingFunc("hello")
//greetingFunc: String => Unit = <function1>
greetingFunc("leo")
// hello,leo

(3)是否有其它方式将函数变为返回值

(除去普通函数转变为变量)
例子: 
            def func1(name:String)=println("Hello, "+name)
            def func2(name:String)=func1(name)
            def func3()=println("Hello!")
            val func4 = func3()  ———— 本质只是返回Unit而已,而不是将函数本身返回了
so:只能用返回匿名函数的方式


(4)匿名函数作为返回值的作用

例子:
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFunc = getGreetingFunc("hello")
greetingFunc("leo")
// hello,leo

val greetingFunc = getGreetingFunc("hi")
greetingFunc("leo")
// hi,leo 

def f(x:Int,y:Int)=x+y
def g(x:Int)=f(x,1)  ————》 函数的返回 

作用: 
更加灵活的定义函数的方式(类似函数的多态)


4.匿名函数当成参数传递

规则: 
(参数名称:参数类型) => {函数体}     ————》 在就是各种省略 
(参数名称:参数类型) => 函数体
(参数名称) => 函数体
(参数名称) => 函数体

特点: 
(1)高阶函数可以自动推断出参数类型,而不需要写明类型
为什么能够自动推断?(定义迭代函数时,必须主动声明类型)
    1>本身在创建非迭代函数时,会依据最后一行的代码,scala可以自己分析返回类型
    2>因为匿名函数肯定是非迭代函数,所以亦可分析
    3>亦或者把迭代函数当成参数传递时,它本身肯定定义了返回值类型,所以亦可分析

(2)只有一个参数的函数,还可以省去其小括号
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")

(3)如果仅有的一个参数在右侧的函数体内只使用一次,则还可以将接收参数省略,并且将参数用_来替代
def triple(func: (Int) => Int)=func(3) 
func: (Int) => Int  :  定义了我要传递 传入参数入Int类型,返回值为Int类型的 函数
func(3)  是 triple函数的返回值

变形;
=》triple(num=>num)
=》3*triple(num=>num)
=》triple(3 * _)

变形的前提:必须有别的算子的加入,不然没有意义 
 例子:直接写  triple( _ )  
scala> triple(_)
res5: (Int => Int) => Int = <function1>
 
深入理解: 仅有一个参数,并且在右侧的函数体内只使用一次
作用:参与后面高阶函数的简写

5.常用的高阶函数

本质理解(它们都以函数为传入参数)
(1)// map: 对传入的每个元素都进行映射,返回一个处理后的元素
Array(1, 2, 3, 4, 5).map(3 * _)

汇总: 享受简写 (当成把参数挨个进行传递后的计算)

Array(1, 2, 3, 4, 5).map((num: Int) => num)   ————》 单个毫无作用
res0: Array[Int] = Array(1, 2, 3, 4, 5)

Array(1, 2, 3, 4, 5).map(3*_)

不使用简写:
Array(1,2,3,4,5).map(new Array(){
        def map(num:Int)=num*3
})

(2) "(1 to 9).map("*" * _).foreach(println _)"

*
**
***
****
*****
******
*******
********

(3) "(1 to 20).filter(_ % 2 == 0)"
对传入的每个元素都进行条件判断,如果对元素返回true,则保留该元素,否则过滤掉该元素

(4)"(1 to 9).reduceLeft( _ * _)"
进行reduce操作,即先对元素1和元素2进行处理,然后将结果与元素3处理,再将结果与元素4处理,
依次类推,即为reduce
// 下面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9
//res10: Int = 362880 

(5)sortWith: 对元素进行两两相比,进行排序
Array(3, 2, 5, 4, 10, 1).sortWith(_ < _)

6.闭包

含义:函数在变量不处于其有效作用域时,还能够对变量进行访问
例子:
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFuncHello = getGreetingFunc("hello")
val greetingFuncHi = getGreetingFunc("hi")

//greetingFuncHello("Tom")  -- hello,Tom
//greetingFuncHi("Tom") -- hi,Tom
逻辑分析:
    1>msg只是存在于匿名函数中的一个局部变量,
    2>在getGreetingFunc执行完之后,还可以继续存在被变量 greetingFuncHello/greetingFuncHi 当做返回值接受的新建函数之中
    3>greetingFuncHello("Tom"),在超出了其作用域的情况下,被再次调用
    4>其中msg变量在被调用时超出了其作用域,还可以使用
    
实现原理:
作为函数对象的实例变量来存储(而不是继续作为局部变量的含义)

7.SAM转换:待续

(1)什么是SAM:
不支持直接将函数传入一个方法作为参数,通常来说,唯一的办法就是定义一个实现了某个接口的类的实例对象,该对象只有一个方法;而这些接口都只有单个的抽象方法,也就是single abstract method,简称为SAM

在scala中的代码实例: (似乎在讲Java )
val button = new JButton("Click")
button.addActionListener(new ActionListener {
  override def actionPerformed(event: ActionEvent) {
    println("Click Me!!!")
  }
})

(2)scala在将java的函数当做变量进行传递时使用隐式转换
隐式转换特性:SAM转换,即将SAM转换为Scala函数
例子:
implicit def getActionListener(actionProcessFunc: (ActionEvent) => Unit) = new ActionListener {
  override def actionPerformed(event: ActionEvent) {
    actionProcessFunc(event)
  }
}
button.addActionListener((event: ActionEvent) => println("Click Me!!!"))

8.Currying 函数(函数柯里化)

含义:将原来接收两个参数的一个函数,转换为两个函数,
             第一个函数接收原先的第一个参数,然后返回接收原先第二个参数的第二个函数
本质:匿名函数的简化语法糖,简化了函数的声明,调用,函数与函数的组合
表现形式:
def sum(a: Int, b: Int) = a + b              //sum(1, 1)
def sum2(a: Int) = (b: Int) => a + b  //sum2(1)(1)
//匿名函数的简写
def sum3(a: Int)(b: Int) = a + b        

复杂调用:
val s1=sum2(1)
val s2 = s1(2)

简单调用:
sum3(1)(2)

作用:
与偏应用函数有关,更加方便了函数与函数之间的组合!!
详解;https://www.cnblogs.com/mataszhang/p/5683654.html

9.scala中带名函数return的使用

return使用的时机:给匿名函数外面的带名函数进行返回值传递
特点:匿名函数中,一定要声明返回的类型
带名函数:有名称的函数(与匿名函数对立)

def greeting(name: String) = {
  def sayHello(name: String):String = {
    return "Hello, " + name
  }
  sayHello(name)
}

10.Lambda表达式

含义:理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。

二:重点的创建规则汇总


1.匿名函数的创建

(函数名: 参数类型) => {方法体}


2.把函数当参数书进行传递  

    (1)以函数作为传入参数的函数的书写规范
函数变量名称 + “:" + "(传参类型)" + “返回值类型” 
func:(String)=>Unit 
例子: 
val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func:(String) => Unit,name:String){ func(name)}
greeting(sayHelloFunc, "leo")
    
(2)将匿名函数直接当成参数传递时的规范
(参数名称:参数类型) => {函数体}     ————》 在就是各种省略 
(参数名称:参数类型) => 函数体
(参数名称) => 函数体
(参数名称) => 函数体

例子: 
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")

3.把函数传递给变量

1》传递普通函数
必须在 ”函数名称“ 后面加上 “空格”和“下划线” ,不带 “()”
例子:
def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _
    
2》传递匿名函数
def 函数名称(传参)=(传入参数)=>{方法体}
例子:def getGreetingFunc(msg:String)=(name:String)=>{println(msg+","+name)} 

猜你喜欢

转载自blog.csdn.net/weixin_39966065/article/details/90173656
今日推荐