Scala

摘要:Scala语言要点
Abstract: Simple Scala

关键字

abstract case catch class
def do else extends
false final finally for
forSome if implicit import
lazy match new null
object override package private
protected return sealed super
this throw trait try
true type val var
while with yield
- : = =>
<- <: <% >:
# @

数据类型

dataType Description
Byte 8 bit signed value. Range from -128 to 127
Short 16 bit signed value. Range -32768 to 32767
Int 32 bit signed value. Range -2147483648 to 2147483647
Long 64 bit signed value. -9223372036854775808 to 9223372036854775807
Float 32 bit IEEE 754 single-precision float
Double 64 bit IEEE 754 double-precision float
Char 16 bit unsigned Unicode character. Range from U+0000 to U+FFFF
String A sequence of Chars
Boolean Either the literal true or the literal false
Unit Corresponds to no value
Null null or empty reference
Nothing The subtype of every other type; includes no values
Any The supertype of any type; any object is of type Any
AnyRef The supertype of any reference type

声明变量和值

val value = 7 //声明值(常量,无法改变)
var variable = 7 //声明变量

赋值语句

赋值语句没有值

y = 1 // 值是()
x = y = 1 //  x = () ; y = 1

控制结构

条件表达式

条件表达式也有值,if/else没有覆盖到的返回无用值(Unit类,等同于void,用()表示)

val s = if (x > 0) 1 else -1 //所有值都有定义
if (x > 0) 1  //else缺失等同于  if (x > 0) 1 else ()

块表达式

包含在{}之间的语句集合为块表达式,块表达式也有值,取最后一个语句的值。

val distance = {val dx = x - x0; val dy = y - y0; sqrt(dx * dx + dy * dy}

循环

for(i <- 表达式) //遍历右边表达式所有值
for(i <- 1 to n)  // i = 1,2...n
for(i <- 1 until n) // i = 1,2...n-1

scala 没有提供 break 和 continue,可以通过以下方式:

import scala.util.control.Breaks._
breakable {
    for (...) {
        if (...) break;
        ...
    }
}

但以上方式使用异常抛出和捕获的形式实现,效率较低。

函数(Functions)

函数定义

def functionName ([list of parameters]) : [return type] = {
   function body
   return [expr]
}

参数列表(List of parameters)和返回值类型(return type)是可选的。例如:

def addInt( a:Int, b:Int ) : Int = {
  var sum:Int = 0
  sum = a + b

  return sum
}
def printMe( ) : Unit = {
    println("Hello, Scala!")
}  

函数调用

[instance.]functionName( list of parameters )

换名调用(Functions Call-by-Name)

一般情况下,调用一个函数的时候,需要传入确定的参数;scala可以把函数作为参数,使得参数的值可以在运行时确定。
scala允许在函数声明和调用该函数参数的地方省略(), 但保留=>

object Test {
   def main(args: Array[String]) {
        delayed(time());
   }

   def time() = {
      println("Getting time in nano seconds")
      System.nanoTime
   }
   //换名调用
   def delayed( t: => Long ) = {
      println("In delayed method")
      println("Param: " + t)
      t
   }
   //普通调用
   def delayed( t():=>Long ) = {
       ...
       t()
   }
}

有名实参(Functions with Named Arguments)

object Test {
   def main(args: Array[String]) {
        printInt(b=5, a=7); 
   }
   def printInt( a:Int, b:Int ) = {
      println("Value of a : " + a );
      println("Value of b : " + b );
   }
}

命名实参的方式允许不按照顺序传入参数。

可变参数(Function with Variable Arguments)

object Test {
   def main(args: Array[String]) {
        printStrings("Hello", "Scala", "Python");
   }
   def printStrings( args:String* ) = {
      var i : Int = 0;
      for( arg <- args ){
         println("Arg value[" + i + "] = " + arg );
         i = i + 1;
      }
   }
}

递归函数(Recursion Functions)

object Test {
   def main(args: Array[String]) {
      for (i <- 1 to 10)
         println( "Factorial of " + i + ": = " + factorial(i) )
   }

   def factorial(n: BigInt): BigInt = {  
      if (n <= 1)
         1  
      else    
      n * factorial(n - 1)
   }
}

默认参数(Default Parameter Values)

object Test {
   def main(args: Array[String]) {
        println( "Returned Value : " + addInt() );
   }
   def addInt( a:Int=5, b:Int=7 ) : Int = {
      var sum:Int = 0
      sum = a + b

      return sum
   }
}

高阶函数(Higher-Order Functions)

高阶函数就是接收函数作为参数,或者返回值是一个函数的函数。

object Test {
   def main(args: Array[String]) {

      println( apply( layout, 10) )

   }

   def apply(f: Int => String, v: Int) = f(v)

   def layout[A](x: A) = "[" + x.toString() + "]"

}

内嵌函数(Nested Functions)

内嵌函数就是在函数内部定义的函数。其作用域只在函数内部有效。

def factorial(i: Int): Int = {
    def fact(i: Int, accumulator: Int): Int = {
     if (i <= 1)
        accumulator
     else
        fact(i - 1, i * accumulator)
    }
    fact(i, 1)
}

匿名函数(Anonymous Functions)

(x:Int) => x+1   //带参数的匿名函数
() => { System.getProperty("user.dir") }  //无参匿名函数
var inc = (x:Int) => x+1 //函数变量

偏函数(Partially Applied Functions)

import java.util.Date

object Test {
   def main(args: Array[String]) {
      val date = new Date
      val logWithDateBound = log(date, _ : String) //绑定日期,message可变

      logWithDateBound("message1" )  //调用时只需要传入message参数
      Thread.sleep(1000)
      logWithDateBound("message2" )
      Thread.sleep(1000)
      logWithDateBound("message3" )
   }

   def log(date: Date, message: String)  = {
     println(date + "----" + message)
   }
}

柯里化函数(Currying Functions)

柯里化是把原本包含多个参数的函数分解为一系列接受单个参数的函数。

def strcat(s1: String) = (s2: String) => s1 + s2

可以理解为:函数strcat(s1: String)返回一个匿名函数 (s2: String) => s1 + s2, 匿名函数的返回值是两个参数之和。

def strcat(s1: String)(s2: String) = s1 + s2 //柯里化简写形式

闭包

闭包是一种特殊的函数,它的返回值依赖于在该函数外部声明的变量。

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
}

类(Class)

声明

class Point(val xc: Int, val yc: Int) {
   var x: Int = xc
   var y: Int = yc
   def move(dx: Int, dy: Int) {
      x = x + dx
      y = y + dy
      println ("Point x location : " + x);
      println ("Point y location : " + y);
   }
}

实例化

val pt = new Point(10, 20);

属性

scala中的属性相当于Java中的private属性加上Getter和Setter方法。有公有属性、类私有属性和对象私有属性三种。
公有属性相当于private字段加上public的Getter和Setter;
类私有属性相当于private字段加上private的Setter和Getter,在类内部的方法可以访问类的私有属性。
对象私有属性相当于只有private字段,只限在对象内部能访问,即使在类内部也不能访问相同类对象的对象私有属性。

1
2
3
4
5
6
7
8
9
class Property {
val p1 = 1 // public 常量
private val p11 = 11 //类私有常量
private[this] val p111 = 111 // 对象私有常量

var p2 = 2 //public 变量
private var p22 = 22 // 类私有变量
private[this] var p222 = 222 // 对象私有变量
}

javap -private Property.class命令反编译一下生成的java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class classes.Property {
private final int p1;
private final int p11;
private final int p111; //对象私有常量不生成getter和setter

private int p2;
private int p22;
private int p222; // 对象私有变量不生成getter和setter

public int p1(); // public常量只生成public getter

private int p11(); // 类私有常量只生成private getter

// public变量生成public getter和setter
public int p2();
public void p2_$eq(int); // Scala的Setter方法
// 类私有变量生成private 的getter和setter
private int p22();
private void p22_$eq(int);
// 主构造方法
public classes.Property();
}

用val声明的常量,在Java中对应final的属性,没有对应的Setter方法。

Scala中的Setter和Getter是分别是属性名()属性名_=()括号可以不写。通常改变属性名的方法使用(),访问属性的只读方法省略().

继承

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 ("Point x location : " + x);
        println ("Point y location : " + y);
        println ("Point z location : " + z);
    }
}

单例对象

scala比Java更加面向对象,其没有static成员,声明并初始化单例对象使用object关键字。

object Test {
   def main(args: Array[String]) {
      val point = new Point(10, 20)
      printPoint

      def printPoint{
         println ("Point x location : " + point.x);
         println ("Point y location : " + point.y);
      }
   }
}

未完待续…

参考

Scala Tutorial