0
点赞
收藏
分享

微信扫一扫

Scala入门教程

互联网码农 2022-01-31 阅读 61



教程目录


  • ​​0x00 教程内容​​
  • ​​0x01 Scala 理论​​

  • ​​1. Scala 基本概念​​
  • ​​2. Scala 交互式命令行​​

  • ​​0x03 Scala 基本语法​​

  • ​​1. 基础语法​​
  • ​​2. 标识符​​
  • ​​3. 注释​​
  • ​​4. 数据类型​​
  • ​​5. 常量和变量​​
  • ​​6. 基本函数​​
  • ​​7. 局部应用​​
  • ​​8. 柯里化函数​​
  • ​​9. 可变长度参数​​
  • ​​10. 类​​
  • ​​11. 构造函数​​
  • ​​12. 继承​​
  • ​​13. 重载方法​​
  • ​​14. 抽象类​​
  • ​​15. 特质​​
  • ​​16. 集合​​

  • ​​0xFF 总结​​


0x00 教程内容


  1. Scala 基础概念、Scala 交互式命令行
  2. Scala 基础语法:值、标识符、注释、数据类型等
  3. Scala 数据类型、常量、变量
  4. Scala 基本函数、局部应用、柯里化函数
  5. Scala 的可变长度参数、类、构造函数、继承
  6. Scala的重载方法、抽象类、特质、集合等



由于是快速入门,所以把一些难点内容忽略了,只把最基础和常用的知识点列举出来,更多学习可以参考Scala官网的指南:​​Scala Tutorial​​ 。



学习前提:需要先安装好Scala的运行环境,教程有很多,可自行在网上搜索。
邵奈一教程:​​分布式集群环境之Scala的安装与配置(Centos7)​​



0x01 Scala 理论

1. Scala 基本概念


Scala是一门多范式的编程语言,一种类似java的编程语言 [1] ,设计初衷是实现可伸缩的语言 [2] 、并集成面向对象编程和函数式编程的各种特性。——摘自百度百科


a. Scala 的特点

主要有:面向对象、函数式编程、静态类型、扩展性、并发性等等,Scala代码是运行于 JVM(Java 虚拟机)上的,可以跟 Java 代码无缝兼容。Scala与Java语言类似,如果有Java基础,学习起Scala语言是比较顺手的,特别是在Java8上引入了​​Lambda​​ 表达式新特性,与Scala的函数式编程语言就更加相似了。

b. Scala 的地位

分布式计算引擎 Spark 主要是由 Scala 编写而成,其中有小部分的 Java ;分布式流处理平台 Kafka 和分布式处理引擎 Flink 也是由 Scala 和 Java编写的;学会 Scala 编程是大数据领域必备的技能。

2. Scala 交互式命令行

想要执行Scala代码可以通过交互式命令方式进行,与 MySQL、Python 等类似。

如果在你本地电脑上安装好了Scala,可以直接运行,如Windows系统:

Scala入门教程_java

如果配置了环境变量,也可以直接在运行界面上输入​​scala​​,然后进入执行界面。

输入简单的代码:

scala> 1 + 1
res0: Int = 2
scala>

代码解释:res0 是解释器自动创建的变量,是表达式的计算结果。类型为 Int ,值为 2。

在Linux或者Mac也一样,直接输入​​scala​​即可进入交互式命令行模式:

Scala入门教程_大数据_02

退出只需要按 Ctrl + D 即可。

0x03 Scala 基本语法

在 Scala 命令行中执行的好处是简单方便,可以快速得到结果,还可以看到返回的类型,如上面的1+1运算,可以看到返回的结果为Int类型,对于初学者比较友好,所以我们接下来主要是在命令行中执行。

1. 基础语法
def HelloWorld() {
println("Hello, shaonaiyi!")
}
HelloWorld()

复制过去,然后回车,即可显示如下结果:

Scala入门教程_scala_03

解释:


  • Scala 语句末尾是不需要分号(​​;​​​)结束的,当然加也可以;Java 是要以分号(​​;​​)结束。
  • ​def main(args: Array[String])​​,main 方法是 Scala 程序的入口,与 Java 一样,每个 Scala 程序都必须定义的。

提示:

  • 如果输入错了,可以多按几个​​回车键​​退出,然后重新输入。
2. 标识符

对象,类,变量和方法的名称称为​​标识符​​。

  1. 字母数字标识符

关键字不能用作标识符,标识符区分大小写。

在 Scala 中标识符只能包括​​字符​​​、​​数字​​​和​​下划线​​​,并且只能以​​字符​​​和​​下划线​​开头,如:hi、_shao、naiyi_888等等。

​$​​字符是Scala中的保留关键字,不应在标识符中使用。

Scala入门教程_scala_04

2. 运算符标识符

运算标识符由一个或多个运算符组成,运算符是可以打印的 ASCII 码,比如:​​+​​​、​​*​​​、​​-​​​、​​/​​​、​​?​​​、​​:​​​、​​~​​等等。

运算标识符有:​​+​​​、​​++​​​、​​:::​​​、​​<?>​​​、​​:>​​等等。

  1. 混合标识符

混合标识符由一个字符数字标识符、下划线和一个运算标识符组成,比如:​​unary_+​​​、​​var_=​​​。在这里,​​unary_+​​​定义了一个一元​​+​​​运算符,​​myvar_=​​用来作为方法名称定义了一个赋值运算符。

  1. 文字标识符

用``(键盘左上角数字1左边按键)符号包含任意字符都是文字标识符,如:

`shaonaiyi`

3. 注释

Scala 中的注释和 Java 中的注释一样:

object HelloWorld {
/*
* 这是块注释
* 这是块注释
*/
def main(args: Array[String]) {
// 这是行注释
println("Hello, shaonaiyi")
}
}
4. 数据类型

Scala 中的数据类型和 Java 完全一样,占用内存和精度也一样。如下表:

数据类型

描述

Byte

8 位有符号值,范围:-128~127

Short

16 位有符号值,范围:-32768~32767

Int

32 位有符号值,范围:-2147483648~2147483647

Long

64 位有符号值,范围: -9223372036854775808~9223372036854775807

Float

32 位 IEEE754 单精度浮点数

Double

64 位 IEEE754 双精度浮点数

Char

16 位无符号 Unicode 字符,范围:U+0000~U+FFFF

String

字符串

Boolean

布尔值:true / false

Unit

表示没有值

Null

空或空引用

Nothing

每一个其他类型的子类型,包括无值

Any

任何类型的超类型,任何 object 都是 Any 类型的

AnyRef

任何引用类型的超类型

说明:上表列出的数据类型都是对象,Scala没有Java中的原生类型,在Scala是可以对数字等基础类型调用方法的。

5. 常量和变量

使用​​val​​​声明常量(也称为​​值​​​),使用​​var​​声明变量。如:

scala> val a = 1
a: Int = 1

scala> a = 2
<console>:12: error: reassignment to val
a = 2
^

scala> var name = "shaonaiyi"
name: String = shaonaiyi

scala> name = "shaonaiyi888"
name: String = shaonaiyi888

scala> name
res2: String = shaonaiyi888

解释:


  • 用val申明的​​a​​是常量,不能重新被赋值,否则会报错。
  • 用var申明的​​name​​是变量,可以重新被赋值。

6. 基本函数

函数的形式如下所示:

def functionName ([list of parameters]) : [return type] = {
function body
return [expr]
}

在 Scala 命令行中,输入如下代码:

def add(a: Int): Int = {
return a + 1
}
var res = add(1)
println(res)

Scala入门教程_大数据_05

代码解释:定义了一个add函数,返回类型为Int,参数a的类型也是Int,返回结果为参数+1,然后调用add函数,结果赋予res。简而言之,这就是一个加1的函数。

简洁写法:


  1. 如果函数​​不带参数​​​,调用函数的时候​​可不写括号​​;
  2. 函数体中的语句如果​​只有一条表达式​​​,可以​​省略函数的大括号​​。

如:

def add(): Int = 1 + 1
var res2 = add
println(res2)

Scala入门教程_scala_06

7. 局部应用

局部应用(Partial application),也译作“偏应用”或“部分应用”;

def add(a: Int, b: Int) :Int = {
return a + b
}
var add1 = add(1, _:Int)
var add2 = add1(2)
println(add2)

Scala入门教程_scala_07

代码解释:定义了一个加法函数add,将其赋值给add1,即add1为新的函数,此处​​add(1, _:Int)​​的 ​​_​​ 则为局部应用的体现,表示任意的参数,类似于一个通配符。 ​​_​​ 也可以表示成一个匿名函数,在此不做过多解释,在大数据的代码中用非常多。​​add1(2)​​,传入了一个参数,自动替换​​add(1, _:Int)​​的 ​​_​​ ,可以简单了解为只是应用了部分的参数。

8. 柯里化函数

柯里化( Currying, 也译作“局部套用”),柯里化指的是将原来接受​​两个​​​参数的函数变成新的接受​​一个​​参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。

想象这样一种情景:一个乘法函数,在一个场景需要选择乘数,而另一个场景需要选择被乘数。

你可以直接传入两个参数,也可以填上第一个参数然后局部应用第二个参数。

def add(x: Int)(y: Int) :Int = {
return x + y
}
var add1 = add(1)(2)
var add2 = add(2) _
var add3 = add2(3)
println(add1)
println(add3)

经过这个过程,就可以实现在你的函数上应用一些参数,然后又应用上另外的一些参数了。

其实这里跟局部应用相类似。

又如下面的一种场景,在scala中定义2个整数相乘运算的函数,具体如下:

​def multiplie2par(x:Int,y:Int)=x*y​

使用柯里化技术可以将上述2个整数的乘法函数改修为接受一个参数的函数,只是该函数返回的是一个以原有第二个参数为参数的函数。

​def multiplie1par(x:Int)=(y:Int)=>x*y​

代码解释:

​multiplie1par(x:Int)​​为接收一个参数的新等价函数,​​(y:Int)=>x*y​​则是新等价函数的返回体,它本身就是一个函数(严格上讲应该是一个匿名函数),参数是除了等价新函数的参数外原函数剩余的参数。其实就是参数 ​​x​​,然后函数体里面的参数为 ​​y​​,变换了位置了。

上述使用柯里化技术得到的等价新函数,在 Scala 语言中还可以进一步简化,将第一个等号去掉,将 ​​=>​​ 写成等号 ​​=​​:

​def multiplie1par1(x:Int)(y:Int)=x*y​

此处与普通函数的区别是这里的两个参数是写成两个括号的,不是一个括号。

9. 可变长度参数

我们可以向方法中传入任意​​多个同类型​​的参数。例如要在多个字符串上执行 String 的 Capitalize 函数:

// 把所有单词改为首字母大写
def capitalizeAll(args: String*) = {
args.map { arg =>
arg.capitalize
}
}
var str = capitalizeAll("shao", "nai", "yi")
println(str)

Scala入门教程_大数据_08

10. 类
class Calculator {
val name: String = "shaonaiyi"
def add(m: Int, n: Int): Int = m + n
}
val calc = new Calculator
println(calc.name)
println(calc.add(1, 1))

Scala入门教程_标识符_09

代码解释:定义了一个 ​​Calculator​​ 类,在类中用 ​​def​​定义方法和用​​val​​定义字段值。

11. 构造函数

构造函数不是特殊的方法,他们是除了类的方法定义之外的代码。增加一个构造函数参数,并用它来初始化内部状态。

// 这是一个构造函数
class Calculator(name: String) {

val color: String = if (name == "shaonaiyi") {
"red"
} else if (name == "shaonaier") {
"green"
} else {
"blue"
}

// 实例方法
def add(m: Int, n: Int): Int = m + n
}
// 使用构造函数来构造一个实例
val calc = new Calculator("shaonaier")
calc.color

Scala入门教程_标识符_10Scala 是高度面向表达式的:大多数东西都是表达式而非指令。我们将颜色的值就是绑定在一个​​​if/else​​表达式上的。

12. 继承
class ScientificCalculator(name: String) extends Calculator(name) {
def log(m: Double, base: Double) = math.log(m) / math.log(base)
}

与Java的集成没区别,也是用 ​​extends​​。

注意: Scala类没有多继承,如:

class Student {
val id: Int = 7
}
class Teacher {
val id: Int = 17
}

假设可以有:

​class TeacherAssistant extends Student, Teacher { ... }​

如果要求返回 ​​id​​​ 时, 就没办法确定返回哪个的 ​​id​​。

13. 重载方法
class EvenMoreScientificCalculator(name: String) extends ScientificCalculator(name) {
def log(m: Int): Double = log(m, math.exp(1))
}

方法重载指的是在一个类中定义多个同名的方法,但要求每个方法具有不同的​​参数类型​​​或​​参数个数​​。

14. 抽象类

你可以定义一个抽象类,它定义了一些方法但没有实现它们。取而代之是由扩展抽象类的子类定义这些方法,你不能创建抽象类的实例。

// 定义抽象类
abstract class Shape {
def getArea():Int // subclass should define this
}

// 扩展抽象类
class Circle(r: Int) extends Shape {
def getArea():Int = { r * r * 3 }
}

val c = new Circle(2)

代码解释:定义了一个抽象类 Shape,里面定义了一个​​getArea​​​的方法,但是没有实现它,而是定义了一个子类 ​​Circle​​​来继承 Shape 抽象类,然后在此子类中进行了 ​​getArea​​ 方法实现。

抽象类定义了一些没有实现的方法,而且抽象类无法被实例化,但可以由抽象类的子类来定义抽象类里面未实现的方法。

15. 特质

特质,是一些字段和行为的集合,可以扩展或混入(mixin)你的类中。不同于类继承,class 可以扩展多个 Traits,与Java中的​​接口​​类似。

trait Car {
val brand: String
}

trait Shiny {
val shineRefraction: Int
}

class BMW extends Car {
val brand = "BMW"
}

val car = new BMW
println(car.brand)

通过 with 关键字,一个类可以扩展多个特质:

class BMW extends Car with Shiny {
val brand = "BMW"
val shineRefraction = 12
}

BMW类继承了Car类,而且混入了 Shiny 类的特质,所以BMW类其实是有两种特点的。

16. 集合

Scala 提供了丰富的集合库,包括:​​列表(List)​​​、​​集合(Set)​​​、​​映射(Map)​​​、​​选项(Option)​​​、​​元组(Tuple)​​:

scala> val x1 = List(1, 2, 3, 4, 5)
x1: List[Int] = List(1, 2, 3, 4, 5)

scala> println(x1)
List(1, 2, 3, 4, 5)

scala> val x2 = Set(1, 2, 3)
x2: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> println(x2)
Set(1, 2, 3)

scala> val x3 = Set(1, 2, 3, 3)
x3: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> println(x3)
Set(1, 2, 3)

scala> val x4 = Map("one" -> 1, "two" -> 2)
x4: scala.collection.immutable.Map[String,Int] = Map(one -> 1, two ->

scala> println(x4)
Map(one -> 1, two -> 2)

scala> val x5 = (2, "two")
x5: (Int, String) = (2,two)

scala> println(x5)
(2,two)

scala> val x6:Option[Int] = Some(5)
x6: Option[Int] = Some(5)

scala> println(x6)
Some(5)

如果有编程基础,相信大家大概也能猜得到含义。此处主要解释Some和Option:


  • Option类型代表任意的值,多用在集合操作中,它可以存储任意类型的值,Option实例就是​​Some​​​或者​​None​​对象实例。
  • ​Some​​​和​​None​​都是它的子类,他们都是final类,所以不能再有派生子类了。
  • Option类型数据可以使用大部分的集合操作,Option数据存取其实是对​​Some​​对象的操作。

请参考此文章:​​Scala:Option、Some、None​​

Scala的其他集合操作详细教程请看:​​Scala常规操作之数组、List、Tuple、Set、Map​​

0xFF 总结


  1. Scala内容比较多,特别是各种各样的算子操作,需要多学习一下,但是入门写个HelloWorld其实此篇文章已经够用了。
  2. 最好大家有Java基础,因为很多内容都是相同的,包括入门大数据,个人也建议应该有个Java基础。

全栈工程师、市场洞察者、专栏编辑

| ​​公众号​​​ | ​​微信​​​ | ​​微博​​ | ​​简书​​ |

福利:

​​邵奈一的技术博客导航​​

​​邵奈一​​ 原创不易,如转载请标明出处。


举报

相关推荐

0 条评论