学习scala第一天

这篇博客详细介绍了Scala的学习历程,从与Java的关系、安装、解释器开始,深入探讨变量、数据类型、函数调用、控制流、函数定义及递归,讲解了默认参数、带名参数和变长参数的使用,并涵盖了Array、ArrayBuffer和Map的操作,展示了函数式编程在数组处理和Map遍历中的应用。

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

第一讲
1.scala与java的关系

scala可以任意调用java的代码

2.scala安装

在PATH环境变量中,配置$SCALA_HOME/bin目录。
在windows命令行内即可直接键入scala,打开scala命令行,进行scala编程。

3.scala解释器

REPL:Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)

4.变量
4.1 计算表达式:

在scala>命令行内,键入scala代码,解释器会直接返回结果给你。如果你没有指定变量来存放这个值,那么值默认的名称为res,而且会显示结果的数据类型,比如Int、Double、String等等。
	 例如,输入1 + 1,会看到res0: Int = 2

4.2 内置变量:

在后面可以继续使用res这个变量,以及它存放的值。
	    ·例如,2.0 * res0,返回res1: Double = 4.0
	    ·例如,"Hi, " + res0,返回res2: String = Hi, 2

4.3自动补全

在scala>命令行内,可以使用Tab键进行自动补全

4.4 声明val变量:


可以声明val变量来存放表达式的计算结果。
例如,val result = 1 + 1
	    ·后续这些常量是可以继续使用的,例如,2 * result
	    ·但是常量声明后,是无法改变它的值的,例如,result = 1,会返回error: reassignment to val的错误信息。

在这里插入图片描述
4.5 声明var变量

如果要声明值可以改变的引用,可以使用var变量。
例如,var myresult = 1,myresult = 2
    ·但是在scala程序中,通常建议使用val,也就是常量

4.6 指定类型

  无论声明val变量,还是声明var变量,都可以手动指定其类型,如果不指定的话,scala会自动根据值,进行类型的推断。

在这里插入图片描述
4.7 声明多个变量:

可以将多个变量放在一起进行声明。

5.数据类型
5.1 基本数据类型:

 	Byte、Char、Short、Int、Long、Float、Double、Boolean。

5.2 类型的加强版类型

scala使用很多加强类给数据类型增加了上百种增强的功能或函数。

5.3 基本操作符

scala的算术操作符与java的算术操作符也没有什么区别,比如+、-、*、/、%等,以及&、|、^、>>、<<等。
	例如:
	比如1 + 1,可以写做1.+(1)

在这里插入图片描述

1.to(10),又可以写做1 to 10

在这里插入图片描述

scala中没有提供++、--操作符,我们只能使用+和-,比如counter = 1,counter++是错误的,必须写做counter += 1.

6.函数调用

6.1  开根号

在这里插入图片描述

6.2   2的4次方

在这里插入图片描述

6.3  取两者中最小值
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191014201244547.png)

7.apply函数
按照索引取

"Hello World"(6),因为在StringOps类中有def apply(n: Int): Char的函数定义,所以"Hello World"(6),实际上是"Hello World".apply(6)的缩写。

在这里插入图片描述

例如,Array(1, 2, 3, 4),实际上是用Array object的apply()函数来创建Array类的实例,也就是一个数组。

`在这里插入图片描述

第二讲
if表达式
1.定义

在Scala中,if表达式是有值的,就是if或者else中最后一行语句返回的值。

在这里插入图片描述

可以将if表达式赋予一个变量,例如,val isAdult = if (age > 18) 1 else 0

在这里插入图片描述
if表达式的类型推断

由于if表达式是有值的,而if和else子句的值类型可能不同,此时if表达式的值是什么类型呢?Scala会自动进行推断,取两个类型的公共父类型。
    ·例如,if(age > 18) 1 else 0,表达式的类型是Int,因为1和0都是Int
    ·例如,if(age > 18) "adult" else 0,此时if和else的值分别是String和Int,则表达式的值是Any,Any是String和Int的公共父类型
    ·如果if后面没有跟else,则默认else的值是Unit,也用()表示,类似于java中的void或者null。例如,val age = 12; if(age > 18) "adult"。此时就相当于if(age > 18) "adult" else ()。

在这里插入图片描述
将if语句放在多行中

默认情况下,REPL只能解释一行语句,但是if表达式通常需要放在多行。
    ·可以使用{}的方式,比如以下方式,或者使用:paste和ctrl+D的方式
 if(age > 18) { "adult" 
} else if(age > 12) "teenager" else "children"

在这里插入图片描述
默认情况下,scala不需要语句终结符,默认将每一行作为一个语句
一行放多条语句
如果一行要放多条语句,则必须使用语句终结符

例如,使用分号作为语句终结符,var a, b, c = 0; if(a < 10) { b = b + 1; c = c + 1 }
    ·通常来说,对于多行语句,还是会使用花括号的方式
if(a < 10) {
    b = b + 1
    c = c + 1
}

在这里插入图片描述
在这里插入图片描述

块表达式
指的就是{}中的值,其中可以包含多条语句,最后一个语句的值就是块表达式的返回值。

var d = if(a < 10) { b = b + 1; c + 1 }

在这里插入图片描述
输入和输出
在这里插入图片描述
循环
while do循环:Scala有while do循环,基本语义与Java相同。

var n = 10
while(n > 0) {
  println(n)
  n -= 1
}

在这里插入图片描述
Scala没有for循环,只能使用while替代for循环,或者使用简易版的for语句

简易版for语句:var n = 10; for(i <- 1 to n) println(i)
    ·或者使用until,表式不达到上限:for(i <- 1 until n) println(i)
    ·也可以对字符串进行遍历,类似于java的增强for循环,for(c <- "Hello World") print(c)

跳出循环语句:scala没有提供类似于java的break语句。
·但是可以使用boolean类型变量、return或者Breaks的break函数来替代使用。

import scala.util.control.Breaks._
breakable {
    var n = 10
    for(c <- "Hello World") {
        if(n == 5) break;
        print(c)
        n -= 1
    }
}

在这里插入图片描述
高级for循环
多重for循环:九九乘法表

for(i <- 1 to 9; j <- 1 to i) {
  if(j == 9) {
    println( i +"*"+j +"="+i * j)
  } else {
    print( i +"*"+j +"="+i * j + "   ")
  }
  if(i==j)
  println(" ")
}

在这里插入图片描述
if守卫:取偶数

for(i <- 1 to 100 if i % 2 == 0) println(i)

在这里插入图片描述
for推导式:构造集合

for(i <- 1 to 10) yield i

在这里插入图片描述

第三讲
函数的定义与调用
在Scala中定义函数时,需要定义函数的函数名、参数、函数体。

def sayHello(name: String, age: Int) = {
  if (age > 18) { printf("hi %s, you are a big boy\n", name); age } 
  else { printf("hi %s, you are a little boy\n", name); age 
}

在这里插入图片描述
在代码块中定义包含多行语句的函数体
单行的函数:def sayHello(name: String) = print("Hello, " + name),如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。与Java中不同,不是使用return返回值的。

def sum(n: Int) = {
  var sum = 0;
  for(i <- 1 to n) sum += i
  sum
}

在这里插入图片描述
** 递归函数与返回类型**
如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型

第四讲
默认参数

在Scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数时使用默认参数。
带名参数
在调用函数时,也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递。
sayHello(firstName = “Mick”, lastName = “Nina”, middleName = “Jack”)
还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面。
sayHello(“Mick”, lastName = “Nina”, middleName = “Jack”)

变长参数
在Scala中,有时我们需要将函数定义为参数个数可变的形式,则此时可以使用变长参数定义函数。

def sum(nums: Int*) = {
  var res = 0
  for (num <- nums) res += num
  res
}

在这里插入图片描述
第五讲
** 使用序列调用变长参数**
在如果想要将一个已有的序列直接调用变长参数函数,是不对的。比如val s = sum(1 to 5)。此时需要使用Scala特殊的语法将参数定义为序列,让Scala解释器能够识别。

val s = sum(1 to 5: _*)

案例:使用递归函数实现累加

def sum2(nums: Int*): Int = {
  if (nums.length == 0) 0
  else nums.head + sum2(nums.tail: _*)
}

在这里插入图片描述
在这里插入图片描述
第六讲
过程的定义
在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。过程通常用于不需要返回值的函数。过程还有一种写法,就是将函数的返回值类型定义为Unit。

def sayHello(name: String) = "Hello, " + name
def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name

第七讲
Array:长度不可改变的数组,字符串数组在底层就是Java的String[],整数数组在底层就是Java的Int[]

val a = new Array[Int](10)
a(0)
a(0) = 1
val a = new Array[String](10)

// 可以直接使用Array()创建数组,元素类型自动推断
val a = Array("hello", "world")
a(0) = "hi"
//可以类型不同
val a = Array("leo", 30)

在这里插入图片描述
** ArrayBuffer**
在Scala中,如果需要类似于Java中的ArrayList这种长度可变的集合类,则可以使用ArrayBuffer。

// 如果不想每次都使用全限定名,则可以预先导入ArrayBuffer类
import scala.collection.mutable.ArrayBuffer
// 使用ArrayBuffer()的方式可以创建一个空的ArrayBuffer
val b = ArrayBuffer[Int]()
// 使用+=操作符,可以添加一个元素,或者多个元素
// 这个语法必须要谨记在心!因为spark源码里大量使用了这种集合操作语法!
b += 1
b += (2, 3, 4, 5)
// 使用++=操作符,可以添加其他集合中的所有元素
b ++= Array(6, 7, 8, 9, 10)
// 使用trimEnd()函数,可以从尾部截断指定个数的元素
b.trimEnd(5)

在这里插入图片描述

// 使用insert()函数可以在指定位置插入元素
// 但是这种操作效率很低,因为需要移动指定位置后的所有元素
b.insert(5, 6)
b.insert(6, 7, 8, 9, 10)
// 使用remove()函数可以移除指定位置的元素
b.remove(1)
删除角标是1到3的元素
b.remove(1, 3)
// Array与ArrayBuffer可以互相进行转换
b.toArray
a.toBuffer

在这里插入图片描述

遍历Array和ArrayBuffer

// 使用for循环和until遍历Array / ArrayBuffer
// 使until是RichInt提供的函数

for (i <- 0 until b.length)
  println(b(i))

在这里插入图片描述

// 跳跃遍历Array / ArrayBuffer

for(i <- 0 until (b.length, 2))
  println(b(i))

在这里插入图片描述

// 从尾部遍历Array / ArrayBuffer

for(i <- (0 until b.length).reverse)
  println(b(i))

在这里插入图片描述

// 使用“增强for循环”遍历Array / ArrayBuffer

for (e <- b)
  println(e)

在这里插入图片描述

数组常见操作

// 数组元素求和
val a = Array(1, 2, 3, 4, 5)
val sum = a.sum

在这里插入图片描述

// 获取数组最大值
val max = a.max

在这里插入图片描述

// 对数组进行排序
scala.util.Sorting.quickSort(a)

在这里插入图片描述

// 获取数组中所有元素内容
a.mkString
a.mkString(", ")
a.mkString("<", ",", ">")

在这里插入图片描述

// toString函数
a.toString
b.toString

在这里插入图片描述
第八讲
使用yield和函数式编程转换数组

// 对Array进行转换,获取的还是Array
val a = Array(1, 2, 3, 4, 5)
val a2 = for (ele <- a) yield ele * ele
a2: Array[Int] = Array(1, 4, 9, 16, 25)

在这里插入图片描述

// 对ArrayBuffer进行转换,获取的还是ArrayBuffer
import scala.collection.mutable.ArrayBuffer
val b = ArrayBuffer[Int]()
b += (1, 2, 3, 4, 5)
val b2 = for (ele <- b) yield ele * ele

在这里插入图片描述

// 结合if守卫,仅转换需要的元素
val a3 = for (ele <- a if ele % 2 == 0 ) yield ele * ele

在这里插入图片描述

// 使用函数式编程转换数组(通常使用第一种方式)
a.filter(_ % 2 == 0).map(2 * _)
a.filter { _ % 2 == 0 } map { 2 * _ }

在这里插入图片描述
** 算法案例:移除第一个负数之后的所有负数**


// 构建数组
val a = ArrayBuffer[Int]()
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)

// 只要第一个负数,后边的不要了,结果:1, 2, 3, 4, 5, -1
var foundFirstNegative = false
var arrayLength = a.length
var index = 0
while (index < arrayLength) {
  if (a(index) >= 0) {
    index += 1
  } else {
    if (!foundFirstNegative) { foundFirstNegative = true; index += 1 }
    else { a.remove(index); arrayLength -= 1 }
  }
} 

在这里插入图片描述
算法案例:移除第一个负数之后的所有负数(数据很多)

// 重新构建数组
val a = ArrayBuffer[Int]()
a += (1, 2, 3, 4, 5, -1, -3, -5, -9,6,7,-7,-3,10)
val b = ArrayBuffer[Int]()
// 每记录所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素
// 性能较高,数组内的元素迁移只要执行一次即可
var foundFirstNegative = false
val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield {
  if (a(i) < 0) foundFirstNegative = true
  i
}
for (i <- keepIndexes) { b+=a(i) }

在这里插入图片描述

第九讲
创建Map

创建不可变的Map
val ages = Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31
创建可变的Map
val ages = scala.collection.mutable.Map("Leo" -> 30, "Jen" -> 25, "Jack" -> 23)
ages("Leo") = 31
使用另外一种方式定义Map元素
val ages = Map(("Leo", 30), ("Jen", 25), ("Jack", 23))

访问Map的元素

// 获取指定key对应的value,如果key不存在,会报错
val leoAge = ages("Leo")
val leoAge = ages("leo")

// 使用contains函数检查key是否存在
val leoAge = if (ages.contains("leo")) ages("leo") else 0

// getOrElse函数
val leoAge = ages.getOrElse("leo", 0)

** 修改Map的元素**

// 更新Map的元素
ages("Leo") = 31
// 增加多个元素
ages += ("Mike" -> 35, "Tom" -> 40)
// 移除元素
ages -= "Mike"
// 更新不可变的map
val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)
// 移除不可变map的元素
val ages3 = ages - "Tom"

Array和ArrayBuffer可变还是不可变是指的长度
Map的可变与不可变是指的Map中是值

** 遍历Map**

// 遍历map的entrySet
for ((key, value) <- ages) println(key + " " + value)
// 遍历map的key
for (key <- ages.keySet) println(key)
// 遍历map的value
for (value <- ages.values) println(value)
// 生成新map,反转key和value
for ((key, value) <- ages) yield (value, key)

在这里插入图片描述
Map的元素类型—Tuple

// 简单Tuple
val t = ("leo", 30)

// 访问Tuple
t._1

// zip操作(拉链操作)
val names = Array("leo", "jack", "mike")
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) println(name + ": " + age)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值