Scala:基础语法

声明变量

1. 声明val变量:可以声明val变量来存放表达式的计算结果

val result = 1 + 1

但是常量声明后,是无法改变它的值的,例如,result = 1,会返回error: reassignment to val的错误信息

2. 声明var变量:如果要声明值可以改变的引用,可以使用var变量。

var myresult = 1;myresult = 2

在scala程序中,通常建议使用val,也就是常量。

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

val name: String = null
val name: Any = "leo"

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

val name1, name2:String = null
val num1, num2 = 100

数据类型与操作符

1. 基本数据类型:
在这里插入图片描述
乍一看与Java的基本数据类型的包装类型相同,但是scala没有基本数据类型与包装类型的概念,统一都是类。scala自己会负责基本数据类型和引用类型的转换操作。

2. 类型的加强版类型
scala使用很多加强类给数据类型增加了上百种增强的功能或函数。
String类通过StringOps类增强了大量的函数,“Hello”.intersect(" World")。
Scala还提供了RichInt、RichDouble、RichChar等类型,RichInt就提供了to函数,1.to(10),此处Int先隐式转换为RichInt,然后再调用其to函数

3. 基本操作符
scala的算术操作符与java的算术操作符也没有什么区别,比如+、-、*、/、%等,以及&、|、^、>>、<<等
scala中没有提供++、–操作符,我们只能使用+和-,比如counter = 1,counter++是错误的,必须写做counter += 1.

4. 转义字符
在这里插入图片描述

函数调用与apply()函数

1. 函数调用方式

import scala.math._,
sqrt(2),pow(2, 4),min(3, Pi)。

不同的一点是,如果调用函数时,不需要传递参数,则scala允许调用函数时省略括号的,例如,“Hello World”.distinct

2. apply函数
Scala中的apply函数是非常特殊的一种函数,在Scala的object中,可以声明apply函数。而使用“类名()”的形式,其实就是“类名.apply()”的一种缩写。通常使用这种方式来构造类的对象,而不是使用“new 类名()”的方式

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

if表达式

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

val age = 30; if (age > 18) 1 else 0

可以将if表达式赋予一个变量

val isAdult = if (age > 18) 1 else 0

2. 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的公共父类型
val age = 12; if(age > 18) "adult" 如果if后面没有跟else,则默认else的值是Unit,也用()表示,类似于java中的void或者null。

3. 将if语句放在多行中
可以使用{}的方式,比如以下方式:

if(age > 18) { "adult" 
} else if(age > 12) "teenager" else "children"

4. if…else if…else 语句

if(布尔表达式 1){
   // 如果布尔表达式 1 为 true 则执行该语句块
}else if(布尔表达式 2){
   // 如果布尔表达式 2 为 true 则执行该语句块
}else if(布尔表达式 3){
   // 如果布尔表达式 3 为 true 则执行该语句块
}else {
   // 如果以上条件都为 false 执行该语句块
}

语句终结符、块表达式

scala不需要语句终结符,默认将每一行作为一个语句

1. 一行放多条语句
如果一行要放多条语句,则必须使用语句终结符

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

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

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

输入和输出

1. print和println:print打印时不会加换行符,而println打印时会加一个换行符。
2. printf 可以用于进行格式化

printf("Hi, my name is %s, I'm %d years old.\n", "Leo", 30)

3. readLine: 允许我们从控制台读取用户输入的数据,类似于java中的System.in和Scanner的作用

循环

在这里插入图片描述
1. while do循环

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

2. Scala没有for循环,只能使用while替代for循环,或者使用简易版的for语句
简易版for语句:var n = 10; for(i <- 1 to n) println(i)
until,表式不达到上限:for(i <- 1 until n) println(i) for(c <- "Hello World") print(c)

3. 跳出循环语句
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
    }
}

4. 高级for循环
多重for循环

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

if守卫:取偶数

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

for推导式:构造集合

for(i <- 1 to 10) yield i

函数的定义与调用

1. 定义函数时
需要定义函数的函数名、参数、函数体

def functionName ([参数列表]) : [return type]

方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。

def functionName ([参数列表]) : [return type] = {
   function body
   return [expr]
}

Scala要求必须给出所有参数的类型,但是不一定给出函数返回值的类型,只要右侧的函数体中不包含递归的语句,Scala就可以自己根据右侧的表达式推断出返回类型

如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。与Java中不同,不是使用return返回值的

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

2. 递归函数与返回类型
如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型

def fab(n: Int): Int = {
  if(n <= 1) 1
  else fab(n - 1) + fab(n - 2)
}

3. 默认参数
在Scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数时使用默认参数

def sayHello(name: String, age: Int = 20) {
  print("Hello, " + name + ", your age is " + age)
}

4. 带名参数
在调用函数时,也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递

def sayHello(firstName: String, middleName: String = "William", lastName: String = "Croft") = firstName + " " + middleName + " " + lastName 
sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")

还可以混合使用未命名参数和带名参数,但是未命名参数必须排在带名参数前面。

sayHello("Mick", lastName = "Nina", middleName = "Jack")

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

def sum(nums: Int*) = {
  var res = 0
  for (num <- nums) res += num
  res
}
sum(1, 2, 3, 4, 5)

5. 使用序列调用变长参数
在如果想要将一个已有的序列直接调用变长参数函数,是不对的。
例: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: _*)
}

6. 过程
在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。过程通常用于不需要返回值的函数。

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

过程还有一种写法,就是将函数的返回值类型定义为Unit

def sayHello(name: String): Unit = "Hello, " + name

lazy值

在Scala中,提供了lazy值的特性,也就是说,如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。

import scala.io.Source._
lazy val lines = fromFile("C://test.txt").mkString

异常

异常捕捉的机制与其他语言中一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在catch字句中,该异常则无法处理,会被升级到调用者处

 try {
    val f = new FileReader("input.txt")
 } catch {
    case ex: FileNotFoundException => {
        println("Missing file exception")
     }
     case ex: IOException => {
        println("IO Exception")
     }
 } finally {
       println("Exiting finally...")
 }

数组

1. Array
Scala 语言中提供的数组是用来存储固定大小的同类型元素,数组对于每一门编辑应语言来说都是重要的数据结构之一。

声明数组变量并不是声明 number0、number1、…、number99 一个个单独的变量,而是声明一个就像 numbers 这样的变量,然后使用 numbers[0]、numbers[1]、…、numbers[99] 来表示一个个单独的变量。数组中某个指定的元素是通过索引来访问的。

数组的第一个元素索引为0,最后一个元素的索引为元素总数减1。

var z:Array[String] = new Array[String](3)
var z = new Array[String](3)

2. ArrayBuffer
在Scala中,如果需要类似于Java中的ArrayList这种长度可变的集合类,则可以使用ArrayBuffer

import scala.collection.mutable.ArrayBuffer

使用ArrayBuffer()的方式可以创建一个空的ArrayBuffer

val b = ArrayBuffer[Int]()

使用+=操作符,可以添加一个元素,或者多个元素

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)
b.remove(1, 3)

Array与ArrayBuffer可以互相进行转换

b.toArray
a.toBuffer

3. 遍历Array和ArrayBuffer
使用for循环和until遍历Array / ArrayBuffer

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)

4. 数组常见操作
在这里插入图片描述

5. 使用yield和函数式编程转换数组
Scala中的yield的主要作用是记住每次迭代中的有关值,并逐一存入到一个数组中。

val a = Array(1, 2, 3, 4, 5)
val a2 = for (ele <- a) yield ele * ele

使用函数式编程转换数组

a.filter(_ % 2 == 0).map(2 * _)

例:移除第一个负数之后的所有负数

import scala.collection.mutable.ArrayBuffer

val a = ArrayBuffer[Int]()
a += (1,2,3,4,5,-1,-3,-5,-9)

//每记录所有不需要移除的元素的索引
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 <- 0 until keepIndexes.length) { 
	a(i) = a(keepIndexes(i))
}

//一次性移除所有需要移除的元素
a.trimEnd(a.length - keepIndexes.length)

print(a)

Scala主要集合结构

1、Scala中的集合体系主要包括:Iterable、Seq(IndexSeq)、Set(SortedSet)、Map(SortedMap)。其中Iterable是所有集合trait的根trait。实际上Seq、Set、和Map都是子trait

  • Seq
    是一个有先后次序的值的序列,比如数组或列表。IndexSeq允许我们通过×××的下表快速的访问任意元素。举例来说,ArrayBuffer是带下标的,但是链表不是。

  • Set
    是一组没有先后次序的值。在SortedSet中,元素以某种排过序顺序被访问。

  • Map
    是一组(键、值)对偶。SortedMap按照键的排序访问其中的实体。

2、 Scala中的集合是分成可变和不可变两类集合的,其中可变集合就是说,集合的元素可以动态修改,而不可变集合的元素在初始化之后,就无法修改了。分别对应scala.collection.mutable和scala.collection.immutable两个包。

3、Seq下包含了Range、ArrayBuffer、List等子trait。其中Range就代表了一个序列,通常可以使用“1 to10”这种语法来产生一个Range。 ArrayBuffer就类似于Java中的ArrayList。

List

List代表一个不可变的列表
List有head和tail,head代表List的第一个元素,tail代表第一个元素之后的所有元素
List有特殊的::操作符,可以用于将head和tail合并成一个List,0 :: list

def decorator(l:List[Int],prefix:String){
   if(l != Nil){
     println(prefix + l.head)
     decorator(l.tail,prefix)
   }
}

增加

A.++(B) --> 在列表A的尾部对添加另外一个列表B,组成一个新的列表
A.++:(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表
A.:::(B) --> 在列表A的首部对添加另外一个列表B,组成一个新的列表
A.:+ (element) -->在列表A的尾部添加一个element,组成一个新的集合
A.+: (element) -->在列表A的首部添加一个element,组成一个新的集合
A.:: (element) -->在列表A的首部添加一个element,组成一个新的集合

删除

drop(n) —>删除list的前n个元素(首部开始删除)
dropRight(n) —>删除list的后n个元素(尾部开始删除)
dropWhile(p: A => Boolean) —>逐个匹配去除符合条件的元素,直到不符合条件,之后的元素不再判断

MutableList

MutableList 由一个单向链表和一个指向该链表终端空节点的指针构成。因为避免了贯穿整个列表去遍历搜索它的终端节点,这就使得列表压缩了操作所用的时间。MutableList 目前是Scala中mutable.LinearSeq 的标准实现

val l = scala.collection.mutable.MutableList (1, 2, 3, 4, 5)

Set

Set代表一个没有重复元素的集合,Set是不保证插入顺序的

val s = new scala.collection.mutable.HashSet[Int]();
s += 1
s += 2
s += 5

LinkedHashSet会用一个链表维护插入顺序

val s = new scala.collection.mutable.LinkedHashSet[Int]();
s += 1
s += 2
s += 5

SrotedSet会自动根据key来进行排序

val s = scala.collection.mutable.SortedSet("orange", "apple", "banana")

Map

1. 创建Map
Map 有两种类型,可变与不可变,区别在于可变对象可以修改它,而不可变对象不可以。

默认情况下 Scala 使用不可变 Map。如果你需要使用可变集合,你需要显式的引入 import scala.collection.mutable.Map 类
在 Scala 中 你可以同时使用可变与不可变 Map,不可变的直接使用 Map,可变的使用 mutable.Map

val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
val x =  scala.collection.mutable.Map("one" -> 1, "two" -> 2, "three" -> 3)

创建空HashMap

val x= new scala.collection.mutable.HashMap[String, Int]

添加 key-value 对,可以使用 + 号

x += ("I" -> 1)
x += ("J" -> 5)
x += ("K" -> 10)
x += ("L" -> 100)

2. 访问Map元素
在这里插入图片描述

获取指定key对应的value,如果key不存在,会报错

val a=x("J")

使用contains函数检查key是否存在

val a = if (x.contains("J")) x("J") else 0
val a= x.getOrElse("J", 0)

3. 修改Map
更新Map的元素

x("J") = 6

增加多个元素

a += ("M" -> 150,"T" -> 180)

移除元素

x -= "T"

更新不可变的map
在这里插入图片描述

移除不可变map的元素

val d = a - "C"

4. 遍历Map
遍历map的entrySet

for ((key, value) <- x) println(key + " " + value)

遍历map的key

for (key <- x.keySet) println(key)

遍历map的value

for (value <- x.values) println(value)

生成新map,反转key和value

for ((key, value) <- x) yield (value, key)

5. 排序Map
SortedMap可以自动对Map的key的排序

val x = scala.collection.immutable.SortedMap("B" -> 2,"A" -> 1,"D" -> 4 ,"C" -> 3)

6. 插入entry的顺序
LinkedHashMap可以记住插入entry的顺序
在这里插入图片描述

7. Map的元素类型—Tuple

val t = ("L",10)

访问Tuple

t._1

8. Map 合并
使用 ++ 运算符或 Map.++() 方法来连接两个 Map,Map 合并时会移除重复的 key

val c1 = Map("A" -> 1,"B" ->2)
val c2 = Map("C" -> 3,"D" ->4)
//  ++ 作为运算符
var c3 = c1 ++ c2
//  ++ 作为方法
 c3 = c1.++(c2)

官方文档:https://www.scala-lang.org/
更多教程:http://www.runoob.com/scala/scala-tutorial.html
https://www.w3cschool.cn/scaladevelopmentguide/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值