Scala学习日记 Day2

本文介绍了Scala中的核心编程概念,包括函数的定义与使用,过程,延迟加载(LazyValue),以及异常处理。文章通过实例展示了Scala如何定义函数,如递归实现斐波那契数列,以及支持默认参数和变长参数的功能。同时,讨论了过程(无返回值的函数)的概念。此外,讲解了延迟加载的两种形式——`lazy`和`def`定义的变量的区别。最后,文章涵盖了异常的抛出与捕获机制,与Java保持一致。
摘要由CSDN通过智能技术生成

工作如何繁忙,生活如何糟心,至少求知的这一刻是我的…

前言

基于Scala 2.12.14。学的《Scala for the Impatient》,记录每天的笔记,有些名词看的英文,翻得未必准确。
适用对象:Java程序员。尽可能在短时间内建立起Java到Scala的转换,做到能看能写。实际上在学习一门语言,应当逐步抛弃掉固有成见,才能发现其中乐趣。人生苦短,别用Java:(逃。

今日重点

了解Scala中的程序控制流,包含有:

  • 函数
  • 过程
  • Lazy Value
  • 异常

函数

函数可以不依赖于对象,方法需要基于一个对象进行操作。Scala中是可以直接定义函数的,而不必像Java一样用静态方法来实现函数。
Scala中函数的定义大体如:

def foo(n: Int): Int = {if (0 < n) 1 else -1}
// 如果还不理解,拆开来看:
// def 定义函数/方法的关键字
// foo 函数名
// n: Int 定义了一个名为n,类型为Int的入参
// : Int = ... 定义了函数返回类型
// {if (0 < n) 1 else -1} 函数内操作,表达式等

Scala编译器支持返回类型自动推导的,只要不是递归函数,就可以省略定义函数返回类型:

def foo(n: Int) = {if (0 < n) 1 else -1}

试想一个斐波那契数的递归实现:

def fac(n: Int): Int = if (n <= 0) 1 else n * fac(n - 1)
// 分支 n <= 0 返回1,尚可推导类型为Int
// 分支 else 对于Scala编译器就无法确定它的类型为Int

默认参数与命名参数

类似Python,Scala允许为方法/函数入参提供默认值,以及通过指定参数命名的方式为特定参数赋值:

def log(info: String, level: String = "INFO", prefix: String = "[", suffix: String = "]") = {
    prefix + " " + level + " " + suffix + info
}
log("sth", suffix="}")
// res4: String = [ INFO }sth

没有指定命名的参数必须在命名参数之前,不能出现:

}
log(suffix="}", "sth")
/*
<console>:13: error: not enough arguments for method log: (info: String, level: String, prefix: String, suffix: String)String.
Unspecified value parameter info.
       log(suffix="a", "a", "debug")
*/

这样是有歧义的,"sth"究竟是哪个参数的值呢?因此异常在预料之中。

变长参数

Scala入参支持变长参数,可以通过循环遍历变长参数或用apply方式访问它的具体index下的值:

def pretty_print(args: Int*) = {
    for (arg <- args) {
        println(arg)
    }
    println(args(0))
}
pretty_print(3, 5, 7)
// 3 5 7 3

在之前我们学过,1 to 3会生成一个[1, 3]区间的序列,但它的类型是Range,要告诉编译器将其转换为Seq:

pretty_print(1 to 3: _*)

_*也就是告知编译器要将参数转换为Seq。

当调用了java方法且其参数为变长Object时,即Object…,需要将基本类型(Scala没有基本类型,只是类比Java的那些类型)转换为Object类型,即Scala中的AnyRef类型:

import java.text.MessageFormat
val str = MessageFormat.format("{0} {1}", "nothing matters", 1.asInstanceOf[AnyRef])
// 试试这个?
// MessageFormat.format("{0} {1}", "nothing matters", 1)

过程

当函数/方法没有返回值时,该函数可被称为过程。还记得上边的pretty_print吗,它就是过程。
没有返回值时,函数的返回值类型可以省略,也可以显式指定Unit:

def pretty_print(args: Int*): Unit = {
    for (arg <- args) {
        println(arg)
    }
}

延迟加载(Lazy Values)

有些对象初始化的代价很大,且使用频度不高甚至未必在应用运行期间使用到,那么可以延迟其初始化到它使用时。
Scala有两种定义惰性变量的关键字,lazy和def:

def lazyDemo(): String = {
    println("lazyDemo")
    return "lazyDemo"
}
lazy val ld = lazyDemo()
// ld: String = <lazy>
ld
// lazyDemo
// res0: String = lazyDemo
ld
// res1: String = lazyDemo

def defDemo(): String = {
    println("defDemo")
    return "defDemo"
}
def dd = defDemo
// dd: String
dd
// defDemo
// res2: String = defDemo
dd
// defDemo
// res3: String = defDemo

def定义的变量在每次使用时都会加载,lazy定义的变量只有在第一次使用时会加载。

异常

抛出异常

和Java一样的抛出异常方式:

throw new RuntimeException()

捕获异常

和Java基本一致,越通用的异常越靠后:

try {
  // do sth
} catch {
  case e: IOException => e.printStackTrace()
  // 不关心的异常可以用_
  case _: RuntimeException => println("it doesn't matters")
}

finally

与Java一致,有try {…} finally {…},也有try {…} catch {…} finally {…}。

有try with resource吗?

很遗憾,没有,要在finally中回收资源。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值