Scala基本知识

scala数据类型

val name: type = initialization
如: val word: String = "hello world"

scala也可以不需要指定类型,通过scala的类型推断机制来推断初始值类型,

如 val word = "hello world"

var和val的区别:var 修饰的对象引用可以改变,val 修饰的则不可改变,但对象的状态却是可以改变的

scala的编码风格推荐在name:type之间加一个空格

scala程序语句结尾没有分号,这是 scala 中约定俗成的编程习惯。大多数情况下分号都是可省的,如果你需要将两条语句写在同一行,则需要用分号分开它们。

scala表达式

如: val i: Int = 1

可以用{}将多行表达式括起来返回,即组合表达式。组合表达式中的最后一个表达式结果成为组合表达式的结果。{}内还可包含if...else...的条件表达式和再嵌套{}

如: val v3: Int = {
   val v5: Int = 5
   val v6: Int = 9
   v5+v6
 }
 println(v3)
/*
    输出14
*/

Unit: scala的一种特殊类型,用来修饰不产生值的表达式,用{}括起来的空集的输出会输出Unit

组合表达式并非必须产生结果,即组合表达式中的表达式不产生结果,组合表达式就不会产生结果,这种组合表达式的类型为Unit

如: val v5 = {val v6 = 0}
/*
输出为(),即Unit类型
*/

3.0+2/5输出3.0,不是3.4,因为2/5 = 0

return表达式,表示“离开此方法并返回值”,如:

if(exp){
    return "It's true"
}
"It's false"

若没有return,则一直返回"It's false"

scala方法

def methodName(arg1:Type1, arg2:Type2, ...): returnType = {
    lines of code
    result
}
  • returnType表示调用方法时方法所产生的结果类型,其中,Unit表示不返回任何结果的方法,默认为Unit
  • result表示最后一行是方法执行完成时返回的结果
  • 方法体是一个表达式
  • assert(boolean表达式,String消息)是scala定义的方法,如果表达式为false,scala就会打印出该消息,并且停止执行该方法中的代码,即抛出异常,下面的代码不再执行,为true不打印消息,继续执行,如assert(result == expected,"xxxx")

scala类

创建类与Java相似,但是创建对象时可以不指定类型,且不需要(),如:

val v = new Hyena

部分类创建时,不需要new关键字,scala允许构建无需使用new就可以被实例化的类,如:

val v = Properties

类中可以访问该类中的其他方法,调用方式与Java一样,如果一个方法的参数列表为空,那么scala允许调用该方法时既可以带(),也可以不带()

类中的实现的方法可以没有名称,初始化时直接调用

class Test(a: Int) {
    for (va <- Range(0, 1)) {
      println(va + a)
    }
}
val v = new Test(2) //> 2

类可以使用类参数进行初始化,类参数列表与方法参数列表一样,但是位于类名的后面,举例如下:

class ClassArgs(a: Int){
 println(f)
 def f(): Int = {
   a * 10
 }
}
val va = new ClassArgs(10)

上例中a在类体的外部是不可访问的,若需要a在类体的外部可见,需要将其定义为参数列表中的varval

class ClassArgs1(var a: Int)
val va2 = new ClassArgs1(10)
va2.a

类可以有多个参数:

class ClassArgs1(a: Int,a1: Int, a2: Int)

类可以支持任意数量的参数(使用*可变元参数列表*,即在末尾加上一个*),方法也可以有可变元参数列表

class ClassArgs1(args: Int*){
    for(n <- args){
        ...
    }
}

尽管所有方法都是在类体的末尾被调用,但是实际上在类体的开头或者任何其他位置也都可以进行调用

类中不能在类体中间放置return,return只用于修饰方法

scala导入和包

指定类名使用import,只与包名、类名有关,与scala文件名无关

import packagename.classname
如:
import util.Random
还支持其他形式:
1. import util.Random, util.Properties
2. import util.{Random,Properties} //在单条import语句中将多个类组合起来
3. import util.{Random => Bob,Properties => Jill} //修改导入类的名字
4. import util._ //下划线表示导入某个包中的所有类 

scala for循环

以下三种for循环方式结果相同,不必声明val i或者给出其类型

for(i <- 0 to 9){}
for(i <- 0 until 10){}
for(i <- Range(0,10))

Range创建0-10但不包括10的值列表,如果想包括10,有以下两种表现形式

1. Range(0,10).inclusive
2. Range(0,11)

scala Vector

  1. Vector不需要任何import语句,Vector属于无需使用new就可以被实例化的类,如:val v1 = Vector(1,3)
  2. ()表示Vector中的索引,索引从0开始,如:v1(0)
  3. Vector可以保存所有不同类型的对象,如:val v1 = Vector("1",3)
  4. Vector对象的sort方法直接修改原Vector,sorted方法产生一个新的Vector,原Vector不变
  5. Vector,List属于不可变集合,优点:可以在多线程之中共享而无需加锁
  6. Vector的所有操作都是O(1)(常数时间),而List对于那些需要访问头部以为元素的操作都需要O(n)操作,所以只在频繁执行头尾分解的情况下,推荐使用List。

除了让scala完成推断类型,也可以指定类型,举例如下:

val v1 = Vector(1,2,3) 
val v2:Vector[Int] = Vector(1,2,3)

其中Int表示类型参数,除了赋值,返回方法时,我们也可以不需要scala推断该方法的返回类型而指定方法的返回类型

scala 模式匹配

match关键字,遇到第一个匹配的即完成模式匹配,然后返回。_表示通配符,可以匹配任何与之前各项都不匹配的值,举例如下:

def matchColor(color: String): String={
 color match {
   case "red" => "RED"
   case "green" => "GREEN"
   case "blue" => "BLUE"
   case _ => "WHITE"
 }
}

scala 具名参数和缺省参数

具名参数

创建具有参数列表的类的实例时,即初始化时,可以指定参数的名字,举例如下:

class Color(red: Int, blue: Int, green: Int)
new Color(red = 80, blue = 9, green = 100)
new Color(80,9,green = 100)

缺省参数

在类的定义中给出缺省值

class Color2(red: Int = 100, blue: Int = 100, green: Int = 100)

具名参数和缺省参数不仅可以用于类,还可以用于方法参数列表

具名参数缺省参数可以和可变元参数列表一起工作。但是,可变元参数列表必须出现在最后,而且,可变元参数列表自身并不支持缺省参数,且无法修改具名参数的定义顺序,举例如下:

class Family(mom: String, dad: String, kids: String*)
new Family(mom="Mom",dad="Dad") //可以
new Family(dad="Dad",mom="Mom",kids="Sammy","Bobby") //不可以

辅助构造器

即使用this关键字重载的构造器叫辅助构造器

辅助构造器必须首先调用*主构造器*,*主构造器*即按照类参数列表和类体而产生的构造器,在Scala中,每个类都有主构造器。主构造器并不以this方法定义,而是与类定义交织在一起,类名之后的(...)即为主构造器的参数。

在辅助构造器中调用主构造器需要使用this关键字而不是类名

辅助构造器注意事项

  • 无需为该辅助构造器声明返回类型
  • 辅助构造器包含=或者不包含=都没有关系
  • 任何辅助构造器第一行必须是对主构造器的调用或对另一个辅助构造器的调用
  • 不能在辅助构造器的参数前面使用var或者val关键字
  • 构造器中的最后一个表达式的值不会被返回

举例如下:

 class Test(a: String = "a", b: String = "test") {
        var result = ""
        def addA(): Unit = {
            result = result + a
        }
        def addB(): Unit = {
            result = result + b
        }
        def this(name: String){
            this("b","t")
        }
        addA()
        addB()
  }

  val v = new Test("Bob")       

case类

在创建主要用于保存数据的类时,可以使用case类,如下:

case class TypeName(arg1:Type, arg2:Type,...)

case类与普通的类很像,case类会自动将所有类参数都创建为val,如果需要某个类参数成为var,那么就在该参数前添加一个val,case类在初始化时不必再使用new关键字,举例如下:

case class Person(first: String, last: String, email: String){}
val p = Person("Jane","Smile","dadsd")

字符串插值

字符串插值允许使用者将变量引用直接插入处理过的字符串。在字符串的前面放置一个s,在想让scala插值的标识符之前放置一个$,也可以将表达式置于${}中间来计算和转换表达式,插值也可以用于case类中。举例如下:

def i(s: String, n: Int, d: Double): String={
    s"first: $s, second: $n, third: $d"
}                                         
i("hi",1,1.3)

def f(n: Int): Int={
    n * 11
}                                         //> f: (n: Int)Int
s"f(7) is ${f(7)}" 

//实测下面两句输出一致,case也可以用new关键字初始化
case class Sky(color: String)
s"""${new Sky("blue")}"""  //三引号除了可以用于换行,若字符串想保留原意(例如三引号中包括引号),也可以使用三引号
s"${new Sky("blue")}"

//实测使用三引号和使用转义符一致
val s1:String = """select * from student where name = "tom""""
val s2 = "select * from student where name = \"tom\""
Share