scala菜鸟笔记
scala编辑形式
1.交互式编程:命令行 println(“HelloWorld!”) ps:后面没有分号
2.脚本:.scala
(1)创建脚本
(2)编译脚本;使用scalac进行编译,把源码编译为字节码。
(3)执行编译脚本;使用scala命令执行命令,把字节码放到虚拟机中解释运行。
scala编辑规范
-
区分大小写 - Scala是大小写敏感的。
-
书写规范 - 对于所有的类名的第一个字母要大写。/如果需要使用几个单词来构成一个类的名称,每个单词的第一个字母要大写。/
所有的方法名称的第一个字母用小写。
程序文件名 - 程序文件的名称应该与对象名称完全匹配(新版本不需要了,但建议保留这种习惯)。 -
入口文件:def main(args: Array[String])- Scala程序从main()方法开始处理,这是每一个Scala程序的强制程序入口部分。。
-
换行符:scala是面向行的语言,语句可以用分号(;)结束或换行符。但是一行多个语句就要用;隔开了
/scala与java最大的区别:scala命令行末尾的;是可选的/ -
注释:与java语言相同 //单行注释 /* */ 多行注释
scala包
-
定义[package]:
方法一(类似java):package [Package_Name] class [Class_Name]
方法二(类似C#):
package [Package_Name]{ class [Class_Name] }
-
引入:[import] /* import语句可以出现在任何地方,而不是只能在文件顶部。*/
(1)import java.awt.Color // 引入Color
(2)import java.awt._ // 引入包内所有成员
(3)如果想要引入包中的几个成员,可以使用selector(选取器):
a. import java.awt.{Color, Font}
b. import java.util.{HashMap => JavaHashMap} // 重命名成员
c. import java.util.{HashMap => , } // 引入了util包的所有成员,但是HashMap被隐藏了 // 隐藏成员
(4) 默认情况下,Scala 总会引入 java.lang. 、 scala. 和 Predef._.
scala变量定义
常量(val)定义
1. val age:Int = 10 //变量声明
2. val age = 10 //变量推断 ps:如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。
3. val age,order = 10 //多个常量声明
变量(var)声明
1.var name = null
2.var greeting = "Hello world"
3.var name,greeting:String = null
懒加载(Lazy val )
lazy val age = 10
(*)基础数据类型
8种基本数据类型[(int、long、float、double、char、byte、short、boolean)
其他数据类型
除去8种基本数据类型,如:String、Unit、Null、Nothing、Any、AnyRef
-
String
字符序列,与java中运行机制差不多,便不多介绍。 -
Unit
表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
且只实现了 Any 类中的三个方法 equals, hashCode 和toString。如果参量是值()则 equals 方法返回 true,否则 false。hashCode 方法返回一个固定的与实现有关的 hash-code 值。toString 方法返回”()”。 -
Null
null 或空引用 -
Nothing
Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 -
Any
Any是所有其他类的超类如果一个类型声明是一个类型的成员声明,该类型的实现可以用任何符合条件L<:T<:U 的类型 T 来实现 t。如果 L 与 U 不一致将会导致编译时错误。边界的某边或全部可被忽略。如果没有给出下界 L,类型 scala.Nothing 就会是默认的下界。如果没有 给出上界 U,类型 scala.Any 就会是默认的上界。
-
AnyRef
AnyRef类是Scala里所有引用类(reference class)的基类
字面值
字面值包括整数,浮点数,字符,布尔值,记号,字符串。这些字面值的语法均和Java 中的字面值一致。
整型字面值
整型字面量用于 Int 类型,如果表示 Long,可以在数字后面添加 L 或者小写 l 作为后缀。
整型字面值通常表示 Int 型,或者后面加上 L 或 l 表示 Long 型。Int 的值的范围是-231 到231-1 间的整数,包含边界值。Long 的值的范围是-263到 263-1 间的整数,包含边界值。整型字面值的值超出以上范围就会导致编译错误。
浮点型字面量
如果浮点数后面有f或者F后缀时,表示这是一个Float类型,否则就是一个Double类型的。
布尔型字面量
布尔型字面值 true 和 false 是 Boolean 类型的成员
符号字面量(字符型字面值)
符号字面量被写成: '<标识符> ,这里 <标识符> 可以是任何字母或数字的标识(注意:不能以数字开头)。这种字面量被映射成预定义类scala.Symbol的实例。
字符型字面值就是单引号括起来的单个字符。字符可以是可打印 unicode 字符或者由一个转义序列描述的 unicode 字符。
字符串字面量
在 Scala 字符串变量使用双引号 " 来定义,如:“HelloWorld”
多行字符串字面量
多行字符串字面值是由三个双引号括起来的字符序列”””…”””。字符序列是除了三个双引号之外的任意字符序列。
Null 值
空值是 scala.Null 类型。Scala.Null和scala.Nothing是用统一的方式处理Scala面向对象类型系统的某些"边界情况"的特殊类型。
转义字符
转义序列
转义字符 | Unicode | 描述 |
---|---|---|
\b | \u0008 | 退格 BS |
\t | \u0090 | 水平制表符 HT |
\n | \u000a | 换行 LF |
\f | \u000c | 格式进纸 FF |
\r | \u000d | 回车 CR |
\” | \u0022 | 双引号 |
\’ | \u0027 | 单引号 |
\ | \u005c | 反斜线 \ |
(*)scala访问修饰符
Scala 访问修饰符基本和Java的一样,分别有:private,protected,public。
与Java相同,如果没有指定访问修饰符,默认情况下,Scala 对象的访问级别都是 public。
但是,Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。
私有(Private)成员
用 private 关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类。他们不能被子类继承,也不能
覆盖父类中的定义。
保护(Protected)成员
在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。
在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。
类的保护成员可以从以下位置访问:
- 定义的类模板内
- 所有以定义的类为基类的模板
- 任何这些类的伴随模块
公共(Public)成员
与java相同,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。
作用域
Scala中,访问修饰符可以通过使用限定词强调。
private[x]
protect[x]
这里的x指代某个所属的包、类或单例对象。如果写成private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private。
运算符
算术运算符
算加(+),减(-),乘(*),除(/)和求余(%)
关系运算符
运算符 | 描述 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
> | 小于 |
>= | 大于等于 |
<= | 小于等于 |
逻辑运算符
运算符 | 名称 | 描述 |
---|---|---|
&& | 逻辑与 | 都为true,则结果为true |
|| | 逻辑或 | 只要有一个为ture,则这结果为ture |
! | 逻辑非 | 指本来值取反 |
位运算符
位运算符用来对二进制位进行操作,~,&,|,^分别为取反,按位与与,按位与或,按位与异或运算
& 如果二进制AND运算符存在于两个操作数中,则二进制AND运算符将对结果复制一位。
| 按位或运算符
运算符 | 名称 | 描述 |
---|---|---|
& | 按位与运算符 | 按位运算,同时都为一,结果也为一 |
| | 按位或运算符 | 按位运算,只要有一位为一,则这结果为一 |
^ | 按位异或运算符 | 按位运算,不同时为一,结果为一 |
~ | 按位取反运算符 | 按位取反 |
<< | 左移动运算符 | 将数据全部向左移一位 |
>> | 右移动运算符 | 将数据全部向左移一位 |
>>> | 无符号右移动运算符 | 表示将运算符左边的对象向右移动运算符右边指定的数,并且在高位补0,其实右移n位,就相当于除于2的n此方 |
赋值运算符
运算符 | 描述 |
---|---|
= | 简单的赋值运算,指定右边操作数赋值给左边的操作数。 |
+= | 相加后再赋值,将左右两边的操作数相加后再赋值给左边的操作数。 |
-= | 相减后再赋值,将左右两边的操作数相减后再赋值给左边的操作数。 |
*= | 相乘后再赋值,将左右两边的操作数相乘后再赋值给左边的操作数。 |
/= | 相除后再赋值,将左右两边的操作数相除后再赋值给左边的操作数 |
%= | 求余后再赋值,将左右两边的操作数求余后再赋值给左边的操作数。 |
<<= | 按位左移后再赋值 |
>>= | 按位右移后再赋值 |
&= | 按位与运算后赋值 |
^= | 按位异或运算符后再赋值 |
|= | 按位或运算后再赋值 |
条件表达式
if语句:
if(布尔表达式)
{
// 如果布尔表达式为 true 则执行该语句块
}
if-else语句:
if( 布尔表达式 ){
// 如果布尔表达式为 true 则执行该语句块
}else{
// 如果布尔表达式为 false 则执行该语句块
}
if-elseif-else语句:
if( 布尔表达式 1 ){
// 如果布尔表达式1为 true 则执行该语句块
}else if(布尔表达式 2 ){
// 如果布尔表达式2为 true 则执行该语句块
}else if( 布尔表达式 3 ){
// 如果布尔表达式3为 true 则执行该语句块
}else{
// 如果布尔表达式1、2、3都为 false则执行该语句块
}
循环结构
while循环
var a = 10;
// while 循环执行
while(a<15 ){
//布尔表达为true执行循环
println( a );
a = a + 1;
}
do-while循环
var a = 10
// do 循环
do{
// 先执行一次循环内部的内容,再进行条件判定
println( "Value of a: " + a );
a = a + 1;
}while( a < 20 )
//括号中的条件表达式为False跳出循环
for循环
var a = 0;
// for 循环
for( a <- 1 to 10){
println( "Value of a: " + a );
}
循环控制
Scala 语言中默认是没有 break 语句,但是你在 Scala 2.8 版本后可以使用另外一种方式来实现 break 语句。当在循环中使用 break 语句,在执行到该语句时,就会中断循环并执行循环体之后的代码块。
// 导入以下包
import scala.util.control._
// 创建 Breaks 对象
val loop = new Breaks;
// 在 breakable 中循环
loop.breakable{
// 循环
for( a <- 1 to 10){
println( "Value of a: " + a );
if(a==13)
// 循环中断
loop.break;
}
}
函数与方法
Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
函数(function)是可以执行的代码块,而方法(method)是通过对象调用的函数。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。
方法
Scala 中的方法跟 Java 的类似,方法是组成类的一部分。
方法声明
def functionName ([参数列表]) : [return type] ={
//方法主体
}
/但是如果不写等号和方法主体,那么方法会被隐式声明为抽象(abstract),包含它的类型也将会是一个抽象类型。/
例如:
object HelloWorld{
def printString( a:String,b:String ) : String={
var c:String = a + b
return c
}
}
当方法没有声明返回值时,默认返回Unit。
方法调用
functionName( 参数列表 )
例如:
def main(args: Array[String]){
var a : String = "Welcome to"
var b : String = " Scala World!"
println(printString(a,b))
}
函数
Scala 中的函数是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象
函数调用
默认调用方式
-
传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
-
传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部‘;使用 => 符号来设置传名调用
指定函数参数名
指定函数参数名,即使传递参数的顺序变化,仍不会影响运行结果。
object HelloWorld{
def printString( a:String,b:String ) : String={
var c:String = a + b
return c
}
def main(args: Array[String]){
println(printString(b=" Scala World!",a="Welcome to" ))
}
}
可变(可重复)参数
Scala 允许指明函数的最后一个参数可以是重复的,即我们不需要指定函数参数的个数,可以向函数传入可变长度参数列表。
通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)。
object HelloWorld{
def printString( a:String*) : Unit = {
println(a)
}
def main(args: Array[String]){
printString("Welcome to" ," Scala World!")
}
}
递归函数
递归函数即函数调用自身。
object Test{
def multiplication( a:Int ) : Int = {
//算出a的阶乘
var b : Int = 0
if(a<=1)
b=1
else
b=a*multiplication(a-1)
return b
}
def main(args: Array[String]){
println(multiplication(5))
}
}
默认参数值
参数在定义函数时已经赋值。
object Test {
def main(args: Array[String]) {
println(getString());
}
def getString( a:String="Hello",b:String=" World!") : String = {
var c : String = null
c = a + b
return c
}
}
函数嵌套
我们可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
object Test {
def main(args: Array[String]) {
for(i <-1 to 9)
multiplication(i)
}
def multiplication(a:Int) : Unit = {
printer(1,a)
def printer(i:Int,a:Int) :Unit = {
if(i<a){
print(i+"*"+a+"="+i*a+" ")
printer(i+1,a)
}else if(i==a){
print(i+"*"+a+"="+i*a+"\n")}
}
}
}
匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。这样操作使代码更加简洁。
例如:
var inc = (x:Int) => x+1
使用方法:
var x = inc(3)-1
多参数匿名函数 形如:
var mul = (x: Int, y: Int) => x*y
-
使用方法相同与单参匿名函数相同,直接调用函数名(参数):
println(mul(3, 4))
无参匿名函数
def main(args: Array[String]) {
var hello = () => {println("HelloWorld!") }
hello()
}
偏应用函数
Scala 偏应用函数是一种表达式,你不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
例如:
object Test {
def main(args: Array[String]) {
val a = 2
val mulBound = mul(a, _ : Int)
mulBound(10)
Thread.sleep(1000)
mulBound(100)
Thread.sleep(1000)
mulBound(1000)
}
def mul(a: Int, b: Int) = {
println(a *b)
}
}
类似与该函数中一个参数一直保持不变或多次使用,我们可以将该参数绑定,第二个参数使用下划线(_)替换缺失的参数列表,并把这个新的函数值的索引的赋给变量。
字符串与数组
字符串
-
创建字符串
var str= "Hello World!"; var str:String = "Hello World!";
-
使用 String Builder 类创建可变字符串
object Test { def main(args: Array[String]) { val buf = new StringBuilder; buf += 'a' buf ++= "bcd" println( buf.toString ); } }
-
利用length()方法字符串长度
[str_name].length()
-
字符串连接
str3=str1.concat(str2);//利用concat方法进行字符串连接 str4=str1+str2//也可以通过+连接
-
格式化输出
object Test { def main(args: Array[String]) { var floatVar = 12.456 var intVar = 2000 var stringVar = "hello" var str = printf("float= %f, int=%d, str= %s", floatVar, intVar, stringVar) //printf在输出时格式化了该数组 println(str) //这里的输出为() } }
数组
Scala 语言中提供的数组是用来存储固定大小的同类型元素。
-
数组的声明及赋值
var z:Array[String] = new Array[String](3) //定义一定长度及格式的空数组 var z = new Array[String](3) //定义一定长度及格式的空数组 z(0) = "abc"; z(1) = "def"; z(2) = "g" //单个元素赋值 var z = Array("abc", "def", "g") //按照集合赋值
-
遍历数组
object Test { def main(args: Array[String]) { var l = Array(5,1,4,3,2) // 类似foreach方法 遍历所有数组元素 for ( x <- l ) { println( x ) } // 利用length方法和for循环,遍历数组 for ( i <- 0 to (l.length - 1)) { println( l(i) ) } } }
-
多维数组
//使用 Array.ofDim方法进行构建多维数组 var list = ofDim[Int](3,3)
-
数组的连接
//利用concat方法进行字符串连接 import Array._ object Test { def main(args: Array[String]) { var l1 = Array(1,2,3,4) var l2 = Array(5,6,7) var l3 = concat( l1,l2) for ( x <- l3 ) { println( x ) } } }
-
变长数组
import scala.collection.mutable.ArrayBuffer //第一步 导scala.collection.mutable.ArrayBuffe包 object Test { def main(args: Array[String]) { val a = ArrayBuffer[Int]() //第二步:创建可变长数组(1) val b = new ArrayBuffer[Int] //第二步:创建可变长数组(2) a+=1 a+=(2,3) //数据追加 b ++= Array(4,5,6) //Array数据追加 a.insert(1,10) //在第2个位置插入10 b.insert(0,7,8,9) //在第1个位置插入7,8,9三个元素 b.trimEnd(2) //trimEnd 删除b数组最后两个元素 printf("Array a:") for ( x <- a ) { print( x+"," ) } printf("\n Array b:") for ( x <- b ) { print( x +",") } } }
最终输出结果:
Array a:1,10,2,3,
Array b:7,1,9,4,
-
(*)数组排序
import scala.collection.mutable.ArrayBuffer //导入此包创建可变长数组 object Test { def main(args:Array[String]) { var a = ArrayBuffer[Int]() //创建可变长数组 a++=Array(1,2,3,4,5,0,5,-1,0,9,-5,-4) exchange(a) } def exchange(a:ArrayBuffer[Int]){ var b = ArrayBuffer[Int]() //创建可变长数组 var c = ArrayBuffer[Int]() //创建可变长数组 for(i<- 0 until a.length){ if(a(i)>=0) //将a中大于等于0的元素都追加给b数组 b += a(i) else c +=a(i) //将a中小于0的元素都追加给c数组 } b = b.sorted //将b数组中的元素升序排列 c=c.arr.sorted.reverse //将c数组中的元素降序排列 println(b) println(c) } }
元组
Scala 中的元组与 Python类似,都由()标识。例:
val t = (1, 2, 3)//定义元组
t._1 //获取元组t第一个元素
t.productElement(0) //获取元组t第一个元素
异常
scala抛出异常与java有些类似
- Scala throw关键字
可以在代码中明确地抛出异常。Scala提供throw关键字来抛出异常。 throw关键字主要用于抛出自定义异常。 - Scala try-catch语句
Scala提供try和catch块来处理异常。try块用于包含可疑代码。catch块用于处理try块中发生的异常。 - finally
finally一般用于在异常时释放资源,如:关闭IO流等。
单例对象与伴生对象
- Scala单例对象
Scala单例对象是十分重要的,没有像在Java一样,有静态类、静态成员、静态方法,但是Scala提供了object对象,这个object对象类似于Java的静态类,它的成员、它的方法都默认是静态的。 - 伴生对象
如果有同样一个类与该object名字一样,则称该object为该类的伴生对象,相对应,该类为object的伴生类。如果一个类有它的伴生对象,这个类就可通过object的名字访问到所有成员,但object不在该类的作用范围。