Scala简介
Scala是一门现代的多范式编程语言,平滑地集成了面向对象和函数式语言的特性。Scala运行于Java平台(JVM,Java 虚拟机)上,并兼容现有的Java程序,Scala代码可以调用Java方法,访问Java字段,继承Java类和实现Java接口。在面向对象方面,Scala是一门非常纯粹的面向对象编程语言。
学习网站
Scala安装
Scala,需要安装相应的编程环境。Scala程序需要运行在JVM(Java虚拟机)上,因此,在安装Scala之前,需要在Windows系统中安装Java,然后,再安装Scala。
Scala官网下安装镜像
bin
下的scala.bat
是交互窗口
可以选择交互式窗口练习语法,当然也可以配置环境变量便于之后IDE的使用。
scala基于jvm运行因此在java的集成开发环境也可以安装相应的插件来使用,推荐一个和Eclipse结合的IDE
http://scala-ide.org/download/sdk.html
下载后是一个压缩包
解压后直接打开eclipse.exe就可以使用
Scala官网
linux系统安装
sudo apt-get install openjdk-7-jre openjdk-7-jdk
安装好jdk后需要配置环境变量。
将下载的scala上传到系统:
解压scala文件:
配置scala的环境变量:
vim /etc/profile
source /etc/profile
重启环境变量。
输入scala
验证是否安装成功:
quit
退出scala
Scala特性
支持的编程范式
Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质描述。类抽象机制的扩展有两种途径。一种途径是子类继承,另一种途径是灵活的混入机制。这两种途径能避免多重继承的种种问题。
函数式编程
Scala也是一种函数式语言,其函数也能当成值来使用。Scala提供了轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。
静态类型
Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。类型系统具体支持以下特性:
-
泛型类别,
-
协变和逆变,
-
标注,
-
类型参数的上下限约束,
-
把类别和抽象类型作为对象成员,
-
复合类型,
-
引用自己时显式指定类型,
-
视图,
-
多态方法。
Scala数据类型
安装完Scala后编写第一个hello world程序。Scala中则必须使用对象方法
object HelloWorld {
def main(args: Array[String]){
println("Hello, World!")
}
}
在scala中scalac
是编译,scala
是运行,和java类似也会产生.class
文件(也可以交互式运行)
scala的基本语法:
Scala 基本语法需要注意以下几点:
-
区分大小写 - Scala是大小写敏感的,这意味着标识Hello 和 hello在Scala中会有不同的含义。
-
类名 - 对于所有的类名的第一个字母要大写。如果需要使用几个单词来构成一个类的名称,每个单词的第一个字母要大写。示例:class MyFirstScalaClass
-
方法名称 - 所有的方法名称的第一个字母用小写。如果若干单词被用于构成方法的名称,则每个单词的第一个字母应大写。示例:def myMethodName()
-
程序文件名 - 程序文件的名称应该与对象名称完全匹配(新版本不需要了,但建议保留这种习惯)。保存文件时,应该保存它使用的对象名称(记住Scala是区分大小写),并追加".scala"为文件扩展名。 (如果文件名和对象名称不匹配,程序将无法编译)。示例: 假设"HelloWorld"是对象的名称。那么该文件应保存为’HelloWorld.scala"
-
def main(args: Array[String]) - Scala程序从main()方法开始处理,这是每一个Scala程序的强制程序入口部分。
Scala 注释
object HelloWorld {
/*
*
* 多行注释
*/
def main(args: Array[String]) {
// 输出 Hello World
// 这是一个单行注释
println("Hello, world!")
}
}
空行和空格
一行中只有空格或者带有注释,Scala 会认为其是空行,会忽略它。标记可以被空格或者注释来分割。
val s = "php中文网"; println(s)
Scala 包
定义包
Scala 使用 package 关键字定义包,在Scala将代码定义到某个包中有两种方式:
第一种方法和 Java 一样,在文件的头定义包名,这种方法就后续所有代码都放在该报中。 比如:
package com.php
class HelloWorld
第二种方法有些类似 C#,第二种方法,可以在一个文件中定义多个包。
package com.php {
class HelloWorld
}
引用包
Scala 使用 import 关键字引用包。
import java.awt.Color // 引入Color
import java.awt._ // 引入包内所有成员
def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent
... // 因为引入了java.awt,所以可以省去前面的部分
}
import语句可以出现在任何地方,而不是只能在文件顶部。import的效果从开始延伸到语句块的结束。这可以大幅减少名称冲突的可能性。
import java.awt.{Color, Font}
// 重命名成员
import java.util.{HashMap => JavaHashMap}
// 隐藏成员
import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了
如果想要引入包中的几个成员,可以使用selector(选取器):
换行符
Scala是面向行的语言,语句可以用分号;
结束或换行符。Scala 程序里,语句末尾的分号通常是可选的。
Scala有两种类型的变量,一种是val,是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值;另一种是var,是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值。
Scala 数据类型
Scala 与 Java有着相同的数据类型,下表列出了 Scala 支持的数据类型:
上表中列出的数据类型都是对象,也就是说scala没有类似java中的基本数据类型。在scala是对数字等基础类型调用方法的。
Scala 基础字面量
整型字面量:整型字面量用于 Int 类型,如果表示 Long,可以在数字后面添加 L 或者小写 l 作为后缀。Byte和short不需要。
浮点型字面量:默认是一个Double类型的,如果是Float需要后面有f或者F后缀。
布尔型字面量:布尔型字面量有 true 和 false。
字符字面量:在scala中字符类型表示为半角单引号(')中的字符。其中 \
表示转移字符。
字符串字面量:字符串表示方法是在双引号中"
包含一系列字符 。
多行字符串的表示方法:多行字符串用三个双引号来表示分隔符,格式为:""" ... """
。
Null 值:空值是 scala.Null 类型。Scala.Null和scala.Nothing是用统一的方式处理Scala面向对象类型系统的某些"边界情况"的特殊类型。
Null类是null引用对象的类型,它是每个引用类(继承自AnyRef的类)的子类。Null不兼容值类型。
Scala 变量
变量是一种使用方便的占位符,用于引用计算机内存地址,变量创建后会占用一定的内存空间。
基于变量的数据类型,操作系统会进行内存分配并且决定什么将被储存在保留内存中。因此,通过给变量分配不同的数据类型,你可以在这些变量中存储整数,小数或者字字母。
变量声明
一、变量: 在程序运行过程中其值可能发生改变的量叫做变量。
二、常量 在程序运行过程中其值不会发生变化的量叫做常量。
在 Scala 中,使用关键词 var
声明变量,使用关键词 “val” 声明常量。
var name : String = "CSDN"
val website : String = "www.csdn.net"
变量类型声明
变量的类型在变量名之后等号之前声明。定义变量的类型的语法格式如下:
var name : String = "CSDN"
在 Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。
var myVar = 10;
val myVal = "Hello, Scala!";
所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值。
这种声明方式和js类似,都是若类型语言。
Scala 多个变量声明
Scala 支持多个变量的声明:
val xmax, ymax = 100 // xmax, ymax都声明为100
如果方法返回值是元组,我们可以使用 val 来声明一个元组:
val (myVar1: Int, myVar2: String) = Pair(40, "Foo")
也可以不指定数据类型:
val (myVar1, myVar2) = Pair(40, "Foo")
scala具有类型推断的能力,也可以显示定义变量。(这点和js有点像,分配内存空间)
Scala 访问修饰符
Scala 访问修饰符基本和Java的一样,分别有:private,protected,public。
如果没有指定访问修饰符符,默认情况下,Scala对象的访问级别都是 public。
Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。
Scala 运算符
和Java基本一致。
Scala循环和条件语句
和Java基本一直。
Scala 函数
函数声明
函数声明通过关键字def
。方法定义由一个def 关键字开始,紧接着是可选的参数列表,一个冒号":" 和方法的返回类型,一个等于号"=",最后是方法的主体。Scala 函数定义格式如下:
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
如果函数没有返回值,可以返回为 Unit,这个类似于 Java 的 void。
如果没有等于号和方法主体,那么方法会被隐式声明为"抽象(abstract)",包含它的类型于是也是一个抽象类型。
函数调用
通过方法名调用:
object MethodTest {
def main(args : Array[String]){
var a:Int =0
a =add(1,3)
print(a)
}
def add(a:Int,b:Int) : Int={
var c:Int = 0
c=a+b
return c
}
}
通过类的实例对象调用:
object Method1 {
def method1():Unit={
print("method1")
}
}
object MethodTest {
def main(args : Array[String]){
//实例化对象
var meth1=
Method1.method1()
}
和js语法一致,不需要像Java一样通过new关键字实例对象,直接引用。
scala的基本数据类型和java类似。
println
用于打印具有换行效果,printf
也用于打印有C语言风格的格式化字符串的效果。
scala写入文件,需要使用java.io.PrintWriter实现把数据写入到文本文件。
scala> import java.io.PrintWriter
import java.io.PrintWriter //这行是Scala解释器执行上面语句后返回的结果
scala> val out = new PrintWriter("output.txt")
out: java.io.PrintWriter = java.io.PrintWriter@25641d39 //这行是Scala解释器执行上面语句后返回的结果
scala> for (i <- 1 to 5) out.println(i)
scala> out.close()
查看写入的文件:
scala读取文件,使用Scala.io.Source的getLines方法实现对文件中所有行的读取。
scala> import scala.io.Source
import scala.io.Source //这行是Scala解释器执行上面语句后返回的结果
scala> val inputFile = Source.fromFile("output.txt")
inputFile: scala.io.BufferedSource = non-empty iterator //这行是Scala解释器执行上面语句后返回的结果
scala> val lines = inputFile.getLines //返回的结果是一个迭代器
lines: Iterator[String] = non-empty iterator //这行是Scala解释器执行上面语句后返回的结果
scala> for (line <- lines) println(line)
1
2
3
4
5
条件语句
val x = 6
if (x>0) {println("This is a positive number")
} else {
println("This is not a positive number")
}
val x = 3
if (x>0) {
println("This is a positive number")
} else if (x==0) {
println("This is a zero")
} else {
println("This is a negative number")
}
循环语句
//while循环
var i = 9
while (i > 0) {
i -= 1
printf("i is %d\n",i)
}
var i = 0
do {
i += 1
println(i)
}while (i<5)
for循环语句格式如下:
for (变量<-表达式) 语句块
其中,“变量<-表达式”被称为“生成器(generator)”
for (i <- 1 to 5) println(i)
for (i <- 1 to 5 by 2) println(i)
scala数据结构,数组是编程中经常用到的数据结构,一般包括定长数组和变长数组。
val intValueArr = new Array[Int](3) //声明一个长度为3的整型数组,每个数组元素初始化为0
intValueArr(0) = 12 //给第1个数组元素赋值为12
intValueArr(1) = 45 //给第2个数组元素赋值为45
intValueArr(2) = 33 //给第3个数组元素赋值为33
val intValueArr = Array(12,45,33)
val myStrArr = Array("BigData","Hadoop","Spark")
scala也有列表,元组的概念。
类和对象是Java、C++等面向对象编程的基础概念。类是用来创建对象的蓝图。定义好类以后,就可以使用new关键字来创建对象。
class Counter{
//这里定义类的字段和方法
}
然后,就可以使用new关键字来生成对象:
new Counter //或者new Counter()
//给类增加字段和方法
class Counter {
private var value = 0
def increment(): Unit = { value += 1}
def current(): Int = {value}
}
Scala数组
数组声明
var z:Array[String] = new Array[String](3)
或
var z = new Array[String](3)
数组使用和Java基本一致
Scala类
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
class Point(xc: Int, yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点: " + x);
println ("y 的坐标点: " + y);
}
}
class Location(override val xc: Int, override val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
println ("z 的坐标点 : " + z);
}
}
override val xc 为重写了父类的字段。
继承会继承父类的所有属性和方法,Scala 只允许继承一个父类。
object
Scala 中定义一个对象由三种方式: object、class 与 trait 。
在Java中一个类可以实例化多个对象。Scala中有很大区别:
object
:单例对象概念
Scala 具有直接创建对象的能力,该对象无需类即可定义其成员。不需要 new,就能直接创建一个对象。而且创建对象的方式和定义类的方式是一样的,唯一的区别就是创建对象要使用 object 关键字。通过 object 直接创建的对象,我们称为单例对象
。 单例对象是没有类就可以存在的对象,这样的对象是独一无二的,不像通过 class 方式可以 new 无数的对象。
那为何 Scala 中程序入口 main() 方法一定要放在 object 创建的单例对象中执行,而不能像 Java 一样?
许多面向对象的编程语言包括 Java 都是使用
static
关键字修饰 main() 方法,这样 main() 方法就变成了类静态方法,这样在类加载完成后就可以直接调用 main() 方法了。但是,Scala 根本就没有 static 关键字, 也没有类静态方法和静态属性。这就是为什么在 Scala 中 main() 方法只能放在 object 定义的单例对象中执行。
伴生对象和伴生类
如果类和单例对象具有相同的名称,那么该类为该对象的同伴类,而该对象为该类的伴生对象 。
伴生对象与伴生类在 Scala 的面向对象编程方法中占据极其重要的位置,主要用于代替 Java 静态成员变量与静态方法,很多 Scala 工具方法都是采用单例对象或伴生对象实现的。
伴生类与伴生对象可以互相访问彼此的私有属性或方法,但是必须都在同一源文件。
class companion{
var a = 23;
var b = 78;
def sum(){
println("The sum is: "+ (a+b));
}
}
object companion{
def main(args:Array[String]){
new companion().sum();
}
}
class
Scala 是一种面向对象的编程语言,所以其定义和使用类的方式和 Java 基本相同,不过 Scala 也有一些不同的地方之处。在scala中由有了新的概念:主构造器,辅助构造器,私有构造器。大概意思就是构造方法,和方法重载发生了一些变化。构造方法用可以用this关键字代替,可以私有化。
trait
在 Scala 中 trait(特征) 相当于 Java 的接口,与接口不同的是它还可以定义属性和方法的实现,这一点又更像 Java 的抽象类。trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
Scala Collection
// 定义整型 List
val x = List(1,2,3,4)
// 定义 Set
var x = Set(1,3,5,7)
// 定义 Map
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
// 创建两个不同类型元素的元组
val x = (10, "php")
// 定义 Option
val x:Option[Int] = Some(5)
Scala 模式匹配
match
关键字对应 Java 里的 switch,但是写在选择器表达式之后。即: 选择器 match {备选项}。
object Test {
def main(args: Array[String]) {
println(matchTest(3))
}
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
}
match 表达式通过以代码编写的先后次序尝试每个模式来完成计算,只要发现有一个匹配的case,剩下的case不会继续匹配。
Scala 异常处理
和Java一致。
Scala提取器
Scala提取器
Scala 文件 I/O
和Java一致。