Scala基础学习笔记

Scala基础

  • 基于JVM
  • Spark使用Scala
  • 大数据基础语言

Spark基于 Scala 2.12

Scala

  • 基于JVM, 基于Java
  • 函数式编程
  • 封装了很多Java的类库
  • 先编译后解释
  • 多范式语言

基础案例:

1
2
3
4
5
object HelloScala{
def main(args: Array[String]): Unit = {
println("hello, scala")
}
}

在IDEA中安装scala插件

配置一个maven scala项目:

  1. 先在main目录下创建scala文件夹, 然后mark as resource root
  2. 邮件整个module/project 添加scala框架支持
  3. 创建scala文件

声明一个单例对象(伴生对象):

1
2
3
4
5
6
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello World Scala")
System.out.println("Hello from Java")
}
}

语法:

main 方法

def 方法名称(参数名: 参数类型): 返回值类型 {方法体}

实现Java类似的面向对象:

Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import scala.swing.MainFrame;

/**
* @Description:
* @Author: klenq
* @CreateTime: 12/26/2021
*/
public class Student {
private String name;
private Integer age;
private static String school = "Good school";
public Student(String name, Integer age){
this.name = name;
this.age = age;
}

public void printInfo(){
System.out.println(this.name + " "+ this.age+" "+ Student.school);
}

public static void main(String[] args){
Student a = new Student("alice", 20);
Student b = new Student("bob", 23);
a.printInfo();
b.printInfo();
}

}

Scala:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student(name: String, age: Int){
def printInfo(): Unit = {
println(name + " " + age + " " + Student.school)
}


}

//引入伴生对象
object Student{
val school: String = "Good School"

def main(args: Array[String]): Unit = {
val alice = new Student("alice",20)
val bob = new Student("bob",23)
alice.printInfo()
bob.printInfo()
}

}

将scala的源码与IDEA关联, 放在scala文件夹下的lib文件夹下

变量和数据类型

注释

与Java的注释语法方式一模一样

变量和常量

基本语法:

  • var 变量名 [:变量类型] = 初始值
  • val 商量名 [:常量类型] = 初始值

能使用常量的地方不用变量

Scala是强类型语言, 自动推断数据类型以后不可以更改数据类型

常量不可更改值, 所有变量都需要有初始值

常量如果使用的是引用数据类型就可以更改其中的属性值(前提属性值也是变量)

标识符:

与Java的区别:

  • 可以用操作符+-*/, 但是就只能是操作符
  • 用反引号`包括的任意字符串, 比如被占用的关键字

换行符

Scala是面向行的语言,语句可以用分号(;)结束或换行符。Scala 程序里,语句末尾的分号通常是可选的。如果你愿意可以输入一个,但若一行里仅 有一个语句也可不写。另一方面,如果一行里写多个语句那么分号是需要的

引用

Scala 使用 import 关键字引用包。

1
2
3
4
5
6
7
import java.awt.Color  // 引入Color

import java.awt._ // 引入包内所有成员

def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent
... // 因为引入了java.awt,所以可以省去前面的部分
}

import语句可以出现在任何地方,而不是只能在文件顶部。import的效果从开始延伸到语句块的结束。这可以大幅减少名称冲突的可能性。

如果想要引入包中的几个成员,可以使用selector(选取器):

1
2
3
4
5
6
7
import java.awt.{Color, Font}

// 重命名成员
import java.util.{HashMap => JavaHashMap}

// 隐藏成员
import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了

注意:默认情况下,Scala 总会引入 java.lang._ 、 scala._ 和 Predef._,这里也能解释,为什么以scala开头的包,在使用时都是省去scala.的。

数据类型

整型字面量

整型字面量用于 Int 类型,如果表示 Long,可以在数字后面添加 L 或者小写 l 作为后缀。

浮点型字面量

如果浮点数后面有f或者F后缀时,表示这是一个Float类型,否则就是一个Double类型的。

字符字面量

在 Scala 字符变量使用单引号 来定义,如下:

1
2
3
4
'a' 
'\u0041'
'\n'
'\t'

字符串字面量:

在 Scala 字符串字面量使用双引号 来定义,如下:

1
2
"Hello,\nWorld!"
"菜鸟教程官网:www.runoob.com"

多行字符串的表示方法:

多行字符串用三个双引号来表示分隔符,格式为:**””” … “””**。

实例如下:

1
2
3
4
5
val foo = """菜鸟教程
www.runoob.com
www.w3cschool.cc
www.runnoob.com
以上三个地址都能访问"""

Null 值

空值是 scala.Null 类型。

Scala.Null和scala.Nothing是用统一的方式处理Scala面向对象类型系统的某些”边界情况”的特殊类型。

Null类是null引用对象的类型,它是每个引用类(继承自AnyRef的类)的子类。Null不兼容值类型。

Scala 访问修饰符

Scala 访问修饰符基本和Java的一样,分别有:private,protected,public。

如果没有指定访问修饰符,默认情况下,Scala 对象的访问级别都是 public。

Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。

1
2
3
4
5
6
7
8
9
10
11
class Outer{
class Inner{
private def f(){
println("f")
}
class InnerMost{
f() // 正确
}
}
(new Inner).f() //错误
}

Java中外部类可以访问内部类的私有成员

Protected

在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。

而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。

1
2
3
4
5
6
7
8
9
10
11
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() //错误
}
}

Public

Scala 中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。

作用域保护

Scala中,访问修饰符可以通过使用限定词强调。格式为:

1
2
3
4
5
private[x] 



protected[x]

这里的x指代某个所属的包、类或单例对象。如果写成private[x],读作”这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private。

这种技巧在横跨了若干包的大型项目中非常有用,它允许你定义一些在你项目的若干子包中可见但对于项目外部的客户却始终不可见的东西。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package bobsrockets{
package navigation{
private[bobsrockets] class Navigator{
protected[navigation] def useStarChart(){}
class LegOfJourney{
private[Navigator] val distance = 100
}
private[this] var speed = 200
}
}
package launch{
import navigation._
object Vehicle{
private[launch] val guide = new Navigator
}
}
}

上述例子中,类 Navigator 被标记为 private[bobsrockets] 就是说这个类对包含在 bobsrockets 包里的所有的类和对象可见。

比如说,从 Vehicle 对象里对 Navigator 的访问是被允许的,因为对象 Vehicle 包含在包 launch 中,而 launch 包在 bobsrockets 中,相反,所有在包 bobsrockets 之外的代码都不能访问类 Navigator。

运算符

与Java基本一致

If Else

与Java基本一致

循环

for循环

语法

Scala 语言中 for 循环的语法:

1
2
3
for( var x <- Range ){
statement(s);
}

以上语法中,Range 可以是一个数字区间表示 i to j ,或者 i until j。左箭头 <- 用于为变量 x 赋值。

也可以使用;实现多个区间

1
2
3
4
5
for(i<- 1 until 10; j <- 1 to 10){
print(i + " ")
print(j + " ")

}

集合循环

1
2
3
for( x <- List ){
statement(s);
}

过滤

Scala 可以使用一个或多个 if 语句来过滤一些元素。

以下是在 for 循环中使用过滤器的语法。

1
2
3
4
5
for( var x <- List
if condition1; if condition2...
){
statement(s);
}

例子

1
2
3
4
5
6
7
8
9
10
11
12
object Test {
def main(args: Array[String]) {
var a = 0;
val numList = List(1,2,3,4,5,6,7,8,9,10);

// for 循环
for( a <- numList
if a != 3; if a < 8 ){
println( "Value of a: " + a );
}
}
}

for 使用 yield

你可以将 for 循环的返回值作为一个变量存储。语法格式如下:

1
2
3
var retVal = for{ var x <- List
if condition1; if condition2...
}yield x

注意大括号中用于保存变量和条件,retVal 是变量, 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。

实例

以下实例演示了 for 循环中使用 yield

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
object Test {
def main(args: Array[String]) {
var a = 0;
val numList = List(1,2,3,4,5,6,7,8,9,10);

// for 循环
var retVal = for{ a <- numList
if a != 3; if a < 8
}yield a

// 输出返回值
for( a <- retVal){
println( "Value of a: " + a );
}
}
}

while循环

与Java基本一致

do while 循环

与Java基本一致

break

Scala 语言中默认是没有 break 语句,但是你在 Scala 2.8 版本后可以使用另外一种方式来实现 break 语句。当在循环中使用 break 语句,在执行到该语句时,就会中断循环并执行循环体之后的代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 导入以下包
import scala.util.control._

// 创建 Breaks 对象
val loop = new Breaks;

// 在 breakable 中循环
loop.breakable{
// 循环
for(...){
....
// 循环中断
loop.break;
}
}

可以break嵌套外层循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var out = new Breaks()
var inner = new Breaks()
out.breakable{
println()
for(i<-1 to 10){
println("outer "+i)
inner.breakable{
for(i<-1 to 10){
println("inner")
out.break()
}
}

}

}

方法/函数

Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。

Scala 中的方法跟 Java 的类似,方法是组成类的一部分。

Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。

Scala 中使用 val 语句可以定义函数,def 语句定义方法。

1
2
3
4
class Test{
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
}

方法声明

Scala 方法声明格式如下:

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

如果你不写等于号和方法主体,那么方法会被隐式声明为**抽象(abstract)**,包含它的类型于是也是一个抽象类型。

Author: klenq
Link: https://klenq.github.io/2021/12/23/Scala基础学习/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.