• Scala的基本语法(三)、函数与方法


    三、函数与方法

    Scala 中 使用val 语句可以定义函数,任何以def 语句定义的都是方法(见《Scala编程》)。Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。

    函数与方法

    默认参数和带名参数

    ​ Scala函数的形参,在声明参数时,可直接赋初始值(默认值),如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值

    ​ 如果存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数

    可变参数

    如(args:Int*),参数为Seq类型的参数,正常情况下参数必须是单个整数,如果传入区间,需要使用:__*

    如果还有其他固定参数,可变参数必须放在最后

    递归与迭代

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

    def test (n: Int) {
        if (n > 2) {
          test (n - 1)
        }//此处加else 打印2 不加else打印 2 3 4 (栈内存中都会开辟4个空间)
        println("n=" + n) // 
      }
    
    1. 程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)

    2. 函数的局部变量是独立的,不会相互影响。引用类型除外

    3. 递归必须向退出递归的条件逼近,否则就是无限递归

    4. 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁。

    5)必须有返回值类型,不然编译器无法校验类型(自动转换是函数结束的时候才能推断)

    • 编写递归函数的关键是找到开始参数和结束条件

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

    ①递归(倒序)

     def peach(day:Int):Int={     //输入天数返回当天的桃子数量
        if(day==10) 1 else (peach(day+1)+1)*2
      }
    
    

    递归时有多个参数且有默认值

    def peach(day:Int,n:Int=1):Int={   //加入有默认值的参数 类型为val
        if(day==10) n else (peach(day+1,n)+1)*2 //迭代时注意参数要一致,此处有默认参数,不写不会报错但结果不对
      }
    

    ②迭代

      def eat(day:Int)={
        var n=1;//后面的n是可变变量 所以n不能直接写在形参里
        for(i<- 1 until day)  n=(n+1)*2  //不包含第10天,所以用until
        n
      }
    

    函数注意事项

    1. 函数的形参列表可以是多个, 如果函数没有形参,定义和调用时,都可以不带()

    2)如果省略= 只做执行代码块用,打印时会返回(),因为一切表达式都有返回值。

    1. 形参列表和返回值列表的数据类型,可以是值类型和引用类型。

    2. scala 函数的形参默认是val的(局部变量),因此不能在函数中进行修改。

    3. 如果函数明确使用return关键字,那么函数类型就不能自行推断了,多种返回类型的可自动或手动指定any

    4. 如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值

    5. Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数/方法中可以再声明/定义函数/方法,类中可以再声明类,方法中可以再声明/定义方法(多个位置不同的同名函数如何使用?)

    6. Scala中的函数可以根据函数体最后一行代码,自行推断函数返回值类型。所以return关键字可以省略。

    7. 递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型

    过程

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

    惰性函数

    ​ 当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数称之为惰性函数,在Java的某些框架代码中称之为懒加载(延迟加载)。

    ​ 1) lazy 不能修饰 var 类型的变量

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

    异常

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

    ​ 按照try—catch- case ex: ArithmeticException =>{} …—finally的方式来处理异常

    Tip

    ​ 在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case子句来匹配异常

    1. 我们将可疑代码封装在try块中。 在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止。

    2. 可以有多个catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大

    3. 常类写在后面,否则编译错误。会提示 “Exception ‘java.lang.xxxxxx’ has already been caught”

    4. Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理。

    5. 用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方

      def test(): Nothing = {
       throw new Exception("不对")
      }
    
    1. finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样。
    2. Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。 它向调用者函数提供了此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。在scala中,可以使用throws注释来声明异常

    异常处理

    中断:breakable(高阶函数) import util.control.Breaks._

    breakable {
          while (n <= 20) {
            n += 1
            if (n == 18) {
              //中断
              //def break(): Nothing = { throw breakException }
              break()
            }
            println("n=" + n)
          }
    
  • 相关阅读:
    使用Node.js创建第一个应用
    Node.js安装
    Node.js简介
    c#中的索引器
    ASP.NET常用内置对象(三)Server
    ASP.NET常用内置对象(二)Response
    ASP.NET常用内置对象(一)Request
    利用JDBC工具类 模拟用户登录!
    JDBC工具类完整版!
    用户登录
  • 原文地址:https://www.cnblogs.com/successok/p/14737328.html
Copyright © 2020-2023  润新知