第5章関数型プログラミングの基礎

関数型プログラミング入門

メソッド、関数、関数型プログラミングと明らかなように、オブジェクト指向プログラミングのスカラ

1. 在scala中,方法和函数几乎可以等同(比如他们的定义、使用、运行机制都一样的),只是函数的使用
方式更加的灵活多样;
2. 函数式编程是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当做一等公民,充分
利用函数、 支持的函数的多种使用方式。比如:在Scala当中,函数是一等公民,像变量一样,既可以作
为函数的参数使用,也可以将函数赋值给一个变量,函数的创建不用依赖于类或者对象,而在Java当中,
函数的创建则要依赖于类、抽象类或者接口;
3. 面向对象编程是以对象为基础的编程方式;
4. 在scala中函数式编程和面向对象编程融合在一起了 。

メソッド、関数、関数型プログラミングおよびオブジェクト指向プログラミングの関係の解析図でスカラ
ダイヤグラム
関数型プログラミングの概要

1. "函数式编程"是一种"编程范式"(programming paradigm);
2. 它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用;
3. 函数式编程中,将函数也当做数据类型,因此可以接受函数当作输入(参数)和输出(返回值);
4. 函数式编程中,最重要的就是函数。

第二に、関数の定義

基本的な構文

	def 函数名 ([参数名: 参数类型], ...)[[: 返回值类型] =] {
		语句...
		return 返回值
	}

概要

1. 函数声明关键字为“def”  (definition);
2. “[参数名: 参数类型], ...”:表示函数的输入(就是参数列表), 可以没有。 如果有,多个参数使用逗号间隔;
3. 函数中的“语句”:表示为了实现某一功能代码块;
4. 函数可以有返回值,也可以没有;
	返回值形式1:	“: 返回值类型 = ”;
	返回值形式2:	“=”	表示返回值类型不确定,使用类型推导完成;
	返回值形式3:	表示没有返回值,return 不生效
5. 如果没有return ,默认以执行到最后一行的结果作为返回值。

サンプルコード:

package com.lj.scala.main

import scala.io.StdIn

/**
  * @author Administrator
  * @create 2020-03-08 12:40
  */
object Funtest01 {

    def main(args: Array[String]): Unit = {

        /**
          * 函数返回值代码测试
          */

        var i = 0
        while (i < 7) {

            print("\n请输入调用方法编号:")
            val num = StdIn.readInt()
            print("请输入姓名:")
            val name = StdIn.readLine()

            if (num == 1) {
                val info = returnValue01(name)
                printInfo(info, name)
            } else if (num == 2) {
                val info = returnValue02(name)
                printInfo(info, name)
            } else if (num == 3) {
                val info = returnValue03(name)
                printInfo(info, name)
            } else {
                println("无调用方法!!!")
            }

            i += 1

        }

    }

    // 打印信息
    def printInfo(info : Any, name: String): Unit ={
        if (info.isInstanceOf[Int]) {
            println(s"$name" + s"的年龄是$info" + "岁!!!")
        } else if (info == ()) {
            println("无返回值信息!!!")
        } else {
            printf("%s的信息是:%s\n", name, info)
        }
    }

    // 1、明确返回值类型
    def returnValue01(name : String): Int = {

        val name_map = Map("Jack" -> 22, "Leo" -> 13, "Rose" -> 27)
        name_map.getOrElse(name, 2)

    }

    // 2、使用类型推导式确定返回值的类型
    def returnValue02(name : String) = {

        val name_map = Map("Jack" -> 22, "Leo" -> 13, "Rose" -> 27, "Amy" -> "老年人",
                        "Maria" -> "学生", "Seven" -> "青年")
        name_map.getOrElse(name, "找不到该人信息")

    }

    // 3、没有返回值,return不生效
    def returnValue03(name : String): Unit ={
        return "无信息"

    }


}
==========================运行结果===========================
请输入调用方法编号:1
请输入姓名:Jack
Jack的年龄是22岁!!!

请输入调用方法编号:1
请输入姓名:Tom
Tom的年龄是2岁!!!

请输入调用方法编号:2
请输入姓名:Leo
Leo的年龄是13岁!!!

请输入调用方法编号:2
请输入姓名:Amy
Amy的信息是:老年人

请输入调用方法编号:2
请输入姓名:Tom
Tom的信息是:找不到该人信息

请输入调用方法编号:3
请输入姓名:Rose
无返回值信息!!!

请输入调用方法编号:3
请输入姓名:Leo
无返回值信息!!!
==========================运行结果===========================

第三に、機能 - 呼び出しメカニズム

ペイント解析機能は、メカニズムを呼び出す必要があります
ここに画像を挿入説明

機能 - 再帰呼び出し

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

再帰関数の基本原則は、(要旨)を観察する必要があります

1. 程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈);
2. 函数的局部变量是独立的,不会相互影响;
3. 递归必须向退出递归的条件逼近,否则就是无限递归,死归了:) ;
4. 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。

再帰のサンプルコード

package com.lj.scala.function

/**
  * @author Administrator
  * @create 2020-03-09 10:08
  */
object FunTest03 {

    def main(args: Array[String]): Unit = {
        
        // 猴子吃桃
        val peach_num = peach(10)
        println("peach_num:" + peach_num)

        // 求函数值
        val fun_num = fun(10)
        println("fun_num:" + fun_num)

        // 求斐波那契数
        val fbn_num = fbn(10)
        println("fbn_num:" + fbn_num)

    }

    /*
        猴子吃桃子问题
        有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃其中的一半,然后再多吃一个。
    当到第十天时,想再吃时(还没吃),发现只有1个桃子了。问题:最初共多少个桃子?
     */

    def peach(day: Int): Int = {

        if (day == 10) {
            1
        } else {
            (peach(day + 1) + 1) * 2
        }

    }

    /*
        求函数值
        已知 f(1)=3; f(n) = 2*f(n-1)+1;
        请使用递归的思想编程,求出 f(n)的值?
     */

    def fun(n: Int): Int = {
        if (n == 1) {
            3
        } else {
            2 * fun(n - 1) + 1
        }
    }

    /*
        斐波那契数
        请使用递归的方式,求出斐波那契数1,1,2,3,5,8,13...
        给你一个整数n,求出它的斐波那契数是多少?
     */

    def fbn(n: Int): Int = {

        if (n == 1 || n == 2) {
            1
        } else {
            fbn(n -1) + fbn(n - 2)
        }

    }

}
==========================运行结果===========================
peach_num:1
fun_num:2047
fbn_num:55
==========================运行结果===========================

第四に、機能の考慮事項と詳細

1. 函数的形参列表可以是多个, 如果函数没有形参,调用时可以不带() ;
2. 形参列表和返回值列表的数据类型可以是值类型和引用类型;
3. Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字
可以省略;
4. 因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略;
5. 如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成“ : 返回类型 =”,
当然如果你什么都不写,即使有return 返回值为();
6. 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值;
7. 如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any);
8. Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数中可以再声明/定义函数,类中
可以再声明类 ,方法中可以再声明/定义方法;
9. Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会
使用默认值,如果指定了实参,则实参会覆盖默认值;
10. 如果函数存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖
默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右]),在这种情况下,
可以采用带名参数明确赋值的变量是哪个;
11. scala函数的形参默认是val的,因此不能在函数中进行修改;
12. 递归函数未执行之前是无法推断出来结果类型,在使用时“必须有明确的返回值类型”;
13. Scala函数支持可变参数;
		示例:
				//支持0到多个参数
				def sum(args :Int*) : Int = { 
				}
				//支持1到多个参数
				def sum(n1: Int, args:  Int*) : Int  = { 
				}
		说明: 
			1. args是集合, 通过 for循环 可以访问到各个值;
			2. 案例演示: 编写一个函数sum ,可以求出1到多个int的和;
			3. 可变参数需要写在形参列表的最后。

第五に、プロセス

基本的な導入

将函数的返回类型为Unit的函数称之为过程(procedure),如果明确函数没有返回值,那么等号可以省略。

ノートと詳細な手順

1. 注意区分: 如果函数声明时没有返回值类型,但是有 = 号,可以进行类型推断最后一行代码。这时这个
函数实际是有返回值的,该函数并不是过程;
2. 开发工具的自动代码补全功能,虽然会自动加上Unit,但是考虑到Scala语言的简单,灵活,最好不加。

第六に、不活性機能

	惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,
无需预先计算它们,这带来了一些好处。首先,您可以将耗时的计算推迟到绝对需要的时候。其次,您
可以创造无限个集合,只要它们继续收到请求,就会继续提供元素。函数的惰性使用让您能够得到更高
效的代码。Java 并没有为惰性提供原生支持,Scala提供了。

入門

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

サンプルコード:

package com.lj.scala.function

/**
  * @author Administrator
  * @create 2020-03-09 11:25
  */
object FunTest04 {


    def main(args: Array[String]): Unit = {

        lazy val res = sum(10, 20)  // 懒加载
        println("--------华丽的分割符-----------")
        println("res:" + res)

    }

    def sum(n1: Int, n2: Int): Int = {

        println("sum()执行了......")
        return n1 + n2

    }

}
==========================运行结果===========================
--------华丽的分割符-----------
sum()执行了......
res:30
==========================运行结果===========================

注意事項や詳細

1. lazy 不能修饰 var 类型的变量;
2. 不但是在调用函数时,加了lazy,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明
了lazy ,那么变量值得分配也会推迟。 比如 lazy val i = 10。

七、異常

入門

	Scala提供try和catch块来处理异常。
	try块用于包含可能出错的代码,catch块用于处理try块中发生的异常。可以根据需要在程序中
有任意数量的try...catch块。

サンプルコード:

package com.lj.scala.function

/**
  * @author Administrator
  * @create 2020-03-09 11:41
  */
object FunTest05 {

    def main(args: Array[String]): Unit = {

        try {
            var num = 99 / 0
        } catch {
            case ex: ArithmeticException => println("捕获了除数为零的算数异常!")
            case ex: Exception => println("捕获了异常!")
        } finally {
            println("Finally...") // 最终都要执行
        }

    }

}
==========================运行结果===========================
捕获了除数为零的算数异常!
Finally...
==========================运行结果===========================

異常概要

1. 我们将可疑代码封装在try块中。 在try块之后使用了一个catch处理程序来捕获异常。如果发生任何
异常,catch处理程序将处理它,程序将不会异常终止;
2. Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异
常这个概念,异常都是在运行的时候捕获处理;
3. 用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,
就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方;
	示例:
		def main(args: Array[String]): Unit = {
			val res = test()
			println(res.toString)
		}
		
		def test(): Nothing = {
			throw new Exception("不对")
		}
4. 在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case子句
来匹配异常。当匹配上后 => 有多条语句可以换行写,类似java的switch case x: 代码块..;
5. 异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch
子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常
写在后,在scala中也不会报错,但这样是非常不好的编程风格;
6. finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工
作,这点和Java一样;
7. Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。 它向调用者函数提供了此方
法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常
终止。

	在scala中,可以使用throws注释来声明异常:

	  @throws(classOf[NumberFormatException]) // 等同于 NumberFormatException.class
	 def thowTest() = {
	 	   "abc".toInt
	  }

学ぶ:北京Shangxue唐漢Shunping教師-シリコンバレーでのScalaのビッグデータ技術はまだされて
ほとんど進展は毎日、多分1日あなたは非常に小さくなります!

公開された20元の記事 ウォンの賞賛6 ビュー20000 +

おすすめ

転載: blog.csdn.net/XuanAlex/article/details/104730464