〇,编程环境
1,安装Java 2,配置Java环境变量 3,安装Scala 4,配置Scala环境变量 参考文末阅读原文链接。
一,算术运算
二,输入输出
输出:println,print,printf 输入:scala.io.StdIn 写文件:java.io.PrintWriter
读文件:scala.io.Source
1,输出
2,输入
3,写文件
4,读文件
三,导入包package
Scala有以下一些常见的导入package的方式
1,引入全部对象 (import scala.io._) 2,引入某个对象 (import scala.io.StdIn) 3,引入某些对象 (import scala.io.{StdIn,Source}) 4,引入后重命名 (import scala.io.{Source => Src,StdIn}) 5,隐藏某些对象 (import scala.io.{Source => _,StdIn}) 6,隐式引入 (java.lang_,scala._,Predef._默认被引入)
四,语法规则
1,标识符 标识符由字母和数字组成,遵循驼峰命名规则。 类和对象的名称以大写字母开头。 方法的名称以小写字母开头。 $可以被用作字母,但要慎重使用。 因为有些特殊符号如 的内部表示为 $plus 当存在标识符和关键字冲突时,可以加上``来避免冲突
2,注释
多行注释用/*开头,以*/结尾。 单行注释用//开头。
3,数据类型
Scala中的数据类型有: Byte,Short,Int,Long,Float, Double,Char,String,Boolean.
以及
Unit(表示无值与C语言void等同,用作无返回值的方法的返回类型), Null(AnyRef的子类,null是它的唯一对象), Nothing(所有类型的子类,它没有对象), Any(所有其他类的超类), AnyRef(所有引用类reference class的超类) ……
4,变量
Scala支持两种类型的变量,即常量val和变量var。 常量在程序中不可以被重新指向,变量可以被重新指向新的对象。 声明变量时可以指定类型,也可以由解释器根据初始值自动推断。
5,标点括号
(1)小括号()用来表示优先级,传入函数参数序列,以及传入容器的下标或key。 (2)中括号[]用来表示容器的元素的数值类型。 (3)大括号{}用来划分作用域,{}的返回值为最后一个语句的值。 (4)句点符号.表示方法,可以用空格代替。 (5)冒号:用来说明变量的数据类型。 (6)=>用来表示匿名函数的映射关系。 (7)->用来指定映射Map中的键值关系。 (8)<-用来指定for表达式的迭代器。 (9)下划线_在Scala中被用作占位符表示匿名函数参数或作为引入package的通配符。
6,编译执行
Scala代码有以下几种执行方式: (1)进入scala解释器交互式执行。 (2)保存成HelloWorld.scala的脚本。
然后在cmd中输入 scala HelloWorld.scala 执行。 (3)使用scalac进行编译然后执行。
scalac HelloWorld.scala,
生成HelloWorld.$class和HelloWorld.class的JVM文件,
再用 scala -classpath . HelloWorld 执行。 (4)使用sbt或者maven等项目管理工具将项目及其依赖编译成jar包, 再通过java -jar HelloWorld.jar执行。
注意当使用第(3)种方法scalac把代码编译时,脚本中必须要定义object单例对象。并且在object对象中实现main方法作为程序入口。
五,Scala数据结构概述
Scala中最常用的数据结构为数组Array以及Collection包中的各种容器类。
按照两个角度进行划分,容器类可以分为可变或者不可变类型,有序或者无序类型。 有序的容器派生类封装在 scala.collection.mutable包中。 无序的容器派生类封装在 scala.collection.immutable包中。 常用的数据结构有以下一些: Array 定长数组:有序,可变类型,长度不可变。
ArrayBuffer 不定长数组:有序,可变类型,长度可以扩展。
List 列表:有序,不可变类型。 Set 集合:无序,不可变类型。 Map 映射:无序,不可变类型。 Tuple 元组:有序,不可变类型,可以存放不同数据类型元素。 Option 选项:表示有可能包含值的容器,也可能不包含值。 Iterator 迭代器:不属于容器,但是提供了遍历容器的方法。 除了Array和ArrayBuffer默认引入的是可变类型外,其它数据结构默认都是不可变的,可以显式地从scala.collection.mutable引入对应可变容器。
六,字符串String
Scala的字符串是一种有序且不可变的基本数据类型,直接使用的Java中定义好的java.lang.String。
1,创建字符串
2,字符串常用操作
七,数组Array
数组Array是一种可变的有序数据结构,但其长度创建后是不可变的,如果要使用长度可变的数组,可以引入ArrayBuffer。
1,创建数组
2,数组常用操作
八,列表List
列表和数组相似,都是有序的结构,但列表中的元素是不可变的。 并且列表的存储结构为递推的链表结构,和数组不同。
1,创建列表
2,列表常用操作
九,集合
集合是一种不可变的类型,并且是无顺序的,适合查找某个元素是否在集合中。
十,映射Map
映射和Python中的字典很像,但是Scala中的Map是一种不可变类型。 如果需要使用可变的Map,需要从scala.collection.mutable引入。
1,创建Map
2,Map常用操作
十一,元组Tuple
元组也是一种不可变的数据结构,其特点是可以存储类型不同的对象。 默认情况下元组的最长长度为22。 使用圆括号括号括起来的几个对象就构成了元组。
十二,迭代器Iterator
迭代器不是一种容器,但是它提供了一种访问容器的方法。 迭代器主要有hasNext和next两个常用方法。
1,创建Iterator
2,使用Iterator
十三,选项Option
Option表示有可能包含值,也可能不包含值的容器。 它有两个子类,一个是Some,一个是对象None。 它的主要方法是getOrElse 和isEmpty。
十四,选择结构
Scala的选择结构主要通过if语句以及match语句实现。 match 语句相当于多分支结构,可以使用模式匹配。
1,if语句
2,match语句
十五,循环结构
Scala循环结构主要是 for循环和while循环,此外还可以使用for推导式。
1,for循环
2,while循环
3,循环控制
4,for表达式的高级用法
在Scala里,一个for表达式可以包含1个或多个「生成器」(Generator)。 其中,每个生成器可以包含0个或多个if「守卫」(Guard)。 以及0个或多个「定义」(Definition)。 以及一个可选的yield子句。 不带yield子句的for表达式叫做for循环。 带有yield子句的for表达式叫做for推导式。
十六,异常捕获
异常捕获的语句是 try...catch...finally... 此外还可以用throw抛出异常。
十七,函数定义
Scala中的函数可以通过关键字def定义或者使用匿名函数。 此处介绍def定义函数的语法。 def functionName(args list) :[return type] = { function body } 当函数的输出类型可以推断时,可以省去“ :[return type]= “。
十八,匿名函数
Scala中的函数是一等公民,可以像变量一样定义和使用。 和变量一样,函数具有类型和值。 函数的类型是函数的参数和返回值的类型映射关系, 如 Int => Unit , (Array[Int],String) => Int 。 函数的值是函数的参数和返回值的取值映射关系, 如 x => x 1 x,y => x y 。 使用这种方式声明的函数叫做匿名函数。 此外,当函数表达式中引用了非参数的变量时,这种函数叫做闭包。 闭包的特性是每次调用它时都会将外部的开放的变量封闭成局部值。 闭包的返回值受外部变量取值变化的影响。
十九,高阶函数
高阶函数即可以传入函数作为其参数的函数。
Scala支持非常强大的函数式编程风格。
函数式编程风格的特点不显式使用循环,而是利用高阶函数调用普通函数在数据上进行遍历操作。
Scala的Array和容器中的各种数据结构内置有非常丰富的高阶函数。
二十,类的定义
Scala中用关键字class定义普通类,用abstract class定义抽象类,用case class定义样例类, 用object定义单例对象,用trait定义特征。 类的定义中可以用private声明为私有属性和私有方法,只允许在类的作用域访问,不允许在类的外部访问。 可以用protected声明为受保护的属性和方法,只允许在类作用域及其子类作用域中访问。 其余属性和方法默认为公有属性和公有方法,可以在类的作用域外访问。 此外还可以在private或protected后面用方括号加上作用域保护,表示方括号中的类和对象不受访问限制。
Scala有3中定义类的风格,java风格,简写风格,和case类风格。 简写风格可以在类声明的参数前加上val即表示为类的属性,省去属性的绑定。 case类本来设计用来进行模式匹配,自带apply和unapply方法,实例化时可以不用new关键字。除了做了优化用于模式匹配,其它方面和普通类没有什么区别。
1,java风格
2,简写风格
3,case类风格
二十一,getter和setter
私有属性可以通过getter和setter方法比较安全地访问和修改。
二十二,构造器
Scala的类包括一个主构造器和若干个(0个或多个)辅助构造器。
主构造器即定义类时传参并用来初始化对象属性的构造器,它是隐含的。
辅助构造器的名称为this,每个辅助构造器都必须调用一个此前已经定义好的主构造器或辅助构造器。
二十三,单例对象和伴生对象
object定义的对象为单例对象,可以直接使用无需实例化。 如果在一个文件有一个object和一个class是同名的,那么这个object称为这个class的伴生对象,这个class称为这个object的伴生类。 伴生对象和伴生类信息可以共享,它们的属性和方法对彼此都是透明的,实际上在编译的时候,会把它们编译成一个Java类,伴生对象定义了这个Java类的静态属性和静态方法。
二十四,继承和特征
Scala可以通过extends关键字指定从某个超类(父类)进行继承。 只有子类的主构造器可以调用超类的主构造器。 子类可以使用super引用超类的某个属性和方法。 子类如果要重写超类的某个属性和方法,需要使用override关键字。 除非超类的该属性和该方法为抽象方法,只有声明没有定义。 如果某个类定义时被abstract声明为抽象类时,它可以被继承但是不能直接被实例化。 和Python语言不同,Scala每个类只能继承一个超类。
为了实现多继承的功能,在指定一个超类的同时可以指定若干个trait特征进行继承。
二十五,apply,unapply和update
当把对一个对象当做函数使用时,会自动调用它的apply方法。 实践中我们一般用apply方法来构造对象,而无需用new声明一个对象,从而相当于一个语法糖。 unapply方法是apply方法的逆方法,我们一般用它来从对象中反推得到其构造参数。 unapply方法通常在模式匹配中会自动被使用。 case类内部实现了apply方法和unapply方法。 当把一个对象当做容器取其某个元素赋值时,会自动调用它的update方法。
1,内部范例
2,apply使用演示
3,unapply使用演示
二十六,Scala语言的设计哲学
1,一切皆对象
从整数,字符串,函数,类到各种数据结构,Scala中一切皆为对象,Any是它们的超类。
2,一切皆表达式
Scala中书写的每条语句都可以看成是一条表达式。
表达式的基本格式是 name:type = {...}
name是对象标识符,type是它的类型,{}括起来的作用域部分都是它的值。
从变量的定义,函数的定义,判断语句,循环语句到类的定义,都可以看成是这个格式省去某些部分的特例或语法糖等价书写形式。
3,简洁而富有表现力
同样的功能,Scala的代码量可能不到Java的五分之一。 并且Scala的许多特性设计非常有表现力。 简洁范例:强大的自动类型推断,隐含类型转换,匿名函数,case类,字符串插值器。 表现力范例:集合的&和|运算,函数定义的=>符号,for循环<-的符号,Map的 ->符号,以及生成range的 1 to 100等表达。
4,函数式编程
函数的特点是操作无副作用,唯一的作用的生成函数值。 把一个函数作用到一些参数上,不会对输入参数造成改变。
为了逼近这个目标,scala设计的默认数据结构绝大部分是不可变的。 并且在一个良好风格的scala程序中,只需要使用val不可变变量而无需使用var可变变量。
显式的for或者while循环是不可取的,让我们用更多的高阶函数吧。
5,多范式编程
尽管函数式编程是Scala的推荐编程范式,但Scala同时混合了强大的命令式编程的功能。 你可以使用强大的for循环,for推导式,使用可变的变量和数据类型实现命令式编程。 你还可以使用强大的模式匹配,基于模式匹配完成复杂的变换操作,实现模式化编程。 最后,正如同它的名字的蕴意,Scala是一门可以伸缩的语言。通过编写扩展类和对象,或继承各种Trait生成新数据结构,Scala可以很容易地成为某个领域的"专业语言"。新增加的那些特性就好像是Scala语法本身的一部分。
Appendix,参考资料
1,林子雨《Spark编程基础》
https://study.163.com/course/courseMain.htm?courseId=1005031005
http://dblab.xmu.edu.cn/blog/spark/ 2,菜鸟教程《Scala教程》
https://www.runoob.com/scala/scala-tutorial.html