scala学习笔记
1.scala与java最大的区别是:scala中的;是可选的,但是如果同一行写了多个语句,那么;是必选的,而java中每条语句后面都需要有;
2.区分大小写
3.所有的类名首字母都要大写,同样使用驼峰的命名方式
4.方法的使用方式使用驼峰的命名的方式,首字母小写
5.程序的文件名必须与对象的名字一致
6.scala包
第一种方法和 Java 一样,在文件的头定义包名,这种方法就后续所有代码都放在该包中
package com.runoob class HelloWorld
第二种方法有些类似 C#
package com.runoob { class HelloWorld }
7.包的引用(import语句可以出现在任何地方,而不是只能在文件顶部。import的效果从开始延伸到语句块的结束。这可以大幅减少名称冲突的可能性。)
import java.awt.Color // 引入Color import java.awt._ // 引入包内所有成员 def handler(evt: event.ActionEvent) { // java.awt.event.ActionEvent ... // 因为引入了java.awt,所以可以省去前面的部分 }
8.如果想要引入包中的几个成员,可以使用selector(选取器)
import java.awt.{Color, Font} // 重命名成员 import java.util.{HashMap => JavaHashMap} // 隐藏成员 import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了
注意:默认情况下,Scala 总会引入 java.lang._ 、 scala._ 和 Predef._,(这里._表示的就是引用这个包的所有成员)这里也能解释,为什么以scala开头的包,在使用时都是省去scala.的。
9.整型字面量用于 Int 类型,如果表示 Long,可以在数字后面添加 L 或者小写 l 作为后缀。
10.如果浮点数后面有f或者F后缀时,表示这是一个Float类型,否则就是一个Double类型的
11.符号字面量被写成: '<标识符> ,这里 <标识符> 可以是任何字母或数字的标识(注意:不能以数字开头),这种字面量被映射成预定义类scala.Symbol的实例。如: 符号字面量 'x 是表达式 scala.Symbol("x") 的简写
12.在scala中字符类型(字符面量)表示为半角单引号(')中的字符,如'a','b'
13.字符串(字符串面量)表示方法是在双引号中(") 包含一系列字符,如"ab","abc" (这里需要注意的时字符串使用的是双引号"",而字符使用的是单引号‘),多行字符串用三个双引号来表示分隔符"""......"""
这里需要注意区分一下 var a = 'a' //这里表示的是字符a var b = "a" //这里表示的是字符串a
14.在 Scala 中,使用关键词 "var" 声明变量,使用关键词 "val" 声明常量。
15.变量的类型在变量名之后等号之前声明(当然变量不一定需要初始值)
var myVar :Int = 10; val myVal :String = "xiong";
16.在 Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。
var myVar = 10; val myVal = "Hello, Scala!";//myVar 会被推断为 Int 类型,myVal 会被推断为 String 类型
17.多个变量的声明
val xmax, ymax = 100 // xmax, ymax都声明为100
scala> val pa = (40,"Foo")//如果方法返回值是元组,我们可以使用 val 来声明一个元组
pa: (Int, String) = (40,Foo)
18.scala访问修饰符
- private(用private关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类)(只能在定义的类,对象或下级类,对象中才能访问)(总的来说,private的范围是类内)
-
class Outer{ class Inner{ private def f(){println("f")} class InnerMost{ f() // 正确 } } (new Inner).f() //错误 }
/*(new Inner).f( ) 访问不合法是因为 f 在 Inner 中被声明为 private,而访问不在类Inner之内。
但在 InnerMost 里访问f就没有问题的,因为这个访问包含在 Inner 类之内。
*/
protected(在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它 -
只允许保护成员在定义了该成员的的类的子类中被访问,
- 而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问)(总的来说,protected的范围是类内和子类)
-
package p{ class Super{ protected def f() {println("f")} } class Sub extends Super{ //Sub继承Super,所以访问f()不会出错 f() } class Other{ (new Super).f()//报错,因为scala中protected的范围与java中不同,所以这里当同一个包里其他类访问protected的就会报错 } }
- public(默认情况下,Scala对象的访问级别都是 public)(在任何地方都可以访问)
19.作用域保护
private[x] 或 protected[x]
/*这里的x指代某个所属的包、类或单例对象。
如果写成private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private*/
package bobsrocckets{ package navigation{ private[bobsrockets] class Navigator{ //这里就表示类Navgator在包bobsrocckets中都是可见的 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而不会报错 } } }
20.for循环
//for循环i到j(包括j)
object Test { def main(args: Array[String]) { var a = 0; // for 循环 for( a <- 1 to 10){ //这里需要注意的一点是:不能再for()里面声明变量,如for(var a <-1 to 10)是会报错的 println( "Value of a: " + a ); } } }
//for循环i到j(不包括j)
object Test { def main(args: Array[String]) { var a = 0; // for 循环 for( a <- 1 until 10){ println( "Value of a: " + a ); } } }
在 for 循环 中你可以使用分号 (;) 来设置多个区间,它将迭代给定区间所有的可能值
object Test { def main(args: Array[String]) { var a = 0; var b = 0; // for 循环 for( a <- 1 to 3; b <- 1 to 3){ println( "Value of a: " + a ); println( "Value of b: " + b ); } } }
//这里就会输出
Value of a: 1
Value of b: 1
Value of a: 1
Value of b: 2
Value of a: 1
Value of b: 3
Value of a: 2
Value of b: 1
Value of a: 2
Value of b: 2
Value of a: 2
Value of b: 3
Value of a: 3
Value of b: 1
Value of a: 3
Value of b: 2
Value of a: 3
Value of b: 3
var a = 0; var b = 0;
// for 循环 for( a <- 1 until 3;a <- 3 to 4){ //输出是分号后面的3,4;循环次数是前面的1 until 3 (就是两次) println( "Value of a: " + a ); //println( "Value of b: " + b ); }
//这里就会输出
Value of a: 3
Value of a: 4
Value of a: 3
Value of a: 4
//如
var a = 0; var b = 0;
// for 循环 for(a <- 3 to 4;a <- 1 until 3){
println( "Value of a: " + a );
//println( "Value of b: " + b );
}
//输出结果为:
Value of a: 1
Value of a: 2
Value of a: 1
Value of a: 2
21.Scala 可以使用一个或多个 if 语句来过滤一些元素。
for( var x <- List if condition1; if condition2... ){ statement(s);
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 ); } } }
value of a: 1 value of a: 2 value of a: 4 value of a: 5 value of a: 6 value of a: 7
22.for使用field
可以将 for 循环的返回值作为一个变量存储
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 ); } } }
value of a: 1
value of a: 2
value of a: 4
value of a: 5
value of a: 6
value of a: 7
22.scala函数( Scala 函数名可以有以下特殊字符:+, ++, ~, &,-, -- , \, /, : 等)
Scala 有函数和方法,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
声明方式:def functionName ([参数列表]) : [return type] {}
object add{ def addInt( a:Int, b:Int ) : Int = { var sum:Int = 0 sum = a + b return sum } }
如果没有返回值,则 object Hello{ def printMe( ) : Unit = { println("Hello, Scala!") } }
23.scala匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。
var inc = (x:Int) => x+1 等价于 def add2 = new Function1[Int,Int]{ def apply(x:Int):Int = x+1; }
var mul = (x: Int, y: Int) => x*y println(mul(3, 4))
24.scala 中没有 static 关键字
所以 对于一个class来说,所有的方法和成员变量在实例被 new 出来之前都是无法访问的
因此class文件中的main方法也就没什么用了
scala object 中所有成员变量和方法默认都是 static 的
因此可以直接访问main方法
25.函数柯里化
柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。
def add(x:Int,y:Int)=x+y 然后 def add(x:Int)=(y:Int)=>x+y 接收一个x为参数,返回一个匿名函数,该匿名函数的定义是:接收一个Int型参数y,函数体为x+y def add(x:Int)(y:Int) = x + y add(1)(2)
实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数 x,返回一个函数类型的值,第二次使用参数y调用这个函数类型的值。
完整代码 object Test { def main(args: Array[String]) { val str1:String = "Hello, " val str2:String = "Scala!" println( "str1 + str2 = " + strcat(str1)(str2) ) } def strcat(s1: String)(s2: String) = { s1 + s2 } } 结果 str1 + str2 = Hello, Scala!
24.scala闭包
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数
object Test { def main(args: Array[String]) { println( "muliplier(1) value = " + multiplier(1) ) println( "muliplier(2) value = " + multiplier(2) ) } var factor = 3 val multiplier = (i:Int) => i * factor //i是形参,factor是自由变量 } 这里我们引入一个自由变量 factor,这个变量定义在函数外面。 这样定义的函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。
25.scala字符串
在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类。(java.lang.String)
在 Scala 中,String 是一个不可变的对象,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象。
但其他对象,如数组就是可变的对象.
如果你需要创建一个可以修改的字符串,可以使用 String Builder 类
object Test { def main(args: Array[String]) { val buf = new StringBuilder; buf += 'a' //这里字符面量使用的是+= buf ++= "bcdef" //这里字符串面量使用的是++= println( "buf is : " + buf.toString ); } } 结果 buf is : abcdef
26.创建格式化字符串
String 类中你可以使用 printf() 方法来格式化字符串并输出,String format() 方法可以返回 String 对象而不是 PrintStream 对象
object Test { def main(args: Array[String]) { var floatVar = 12.456 var intVar = 2000 var stringVar = "菜鸟教程!" var fs = printf("浮点型变量为 " + "%f, 整型变量为 %d, 字符串为 " + " %s", floatVar, intVar, stringVar) println(fs) } } 结果 浮点型变量为 12.456000, 整型变量为 2000, 字符串为 菜鸟教程!()
27. Scala中::,+:,:+,:::的区别
-
::
该方法被称为cons,意为构造,向队列的头部追加数据,创造新的列表。用法为x::list
,其中x
为加入到头部的元素,无论x
是列表与否,它都只将成为新生成列表的第一个元素,也就是说新生成的列表长度为list的长度+1(btw,x::list
等价于list.::(x)
) -
:+
和+:
两者的区别在于:+
方法用于在尾部追加元素,+:
方法用于在头部追加元素,和::
很类似,但是::
可以用于pattern match ,而+:
则不行. 关于+:
和:+
,只要记住冒号永远靠近集合类型就OK了(加号在后就后面添加,加号在前面就前面添加)。 -
++
该方法用于连接两个集合,list1++list2
-
:::
该方法只能用于连接两个List类型的集合
28.Scala迭代器
object Test{ def main(args:Array[String]){ val it = Iterator(1111,2222,3333); var a = it.max;//这里迭代器就已经迭代到最有了 var c = it.hasNext;//所以这里it就没有元素了,所hasNext返回false println(a); println(c); } }