Scala语法
变量
val a: Int = 3
函数
函数文本:function literal
函数文本被编译进一个类,类在运行期实例化的时候是一个函数值。函数文本和值的区别在于函数文本存在于源代码,而函数值存在于运行期对象。
都是函数特质trait Function[-S,+T]的实例
args.foreach(arg => println(arg))
函数文本的语法就是,括号里的命名参数列表,右箭头,然后是函数体。语法入下图所示:
集合
Array可变,List,Tuple不可变
val a = Array(1,2,3) //Array[Int]
a(0) //1 //a.apply(0)
a(0) = 4 //a.update(0, 4)
val l = List(1,2,3) //List[Int]
l(1) //2
val t = (1,2,3) //Tuple[Int, Int, Int]
t._1 //1
//immutable mutable set
import scala.collection.mutable.Set //还有import scala.collection.immutable.Set
val movieSet = Set("Hitch", "Poltergeist") //scala.collection.mutable.Set[String]
movieSet += "Shrek"
//immutable mutable map
import scala.collection.mutable.Map
val treasureMap = Map[Int, String]()
treasureMap += (1 -> "Go to island.")
treasureMap += (2 -> "Find big X on ground.")
treasureMap += (3 -> "Dig.")
println(treasureMap(2))
//1 -> "Go to island"这样的二元操作符表达式转换为(1).->("Go to island.")。并返回一个包含键和值的二元元组
val romanNumeral = Map(
1 -> "I", 2 -> "II", 3 -> "III", 4 -> "IV", 5 -> "V"
)
println(romanNumeral(4))
//第一行里提及Map时,你会得到缺省的映射:scala.collection.immutable.Map
Singleton对象
scala没有static成员,替代品是Singleton object
函数式对象 对象状态不可改变
Scala编译器将把你放在类内部的任何不是字段的部分或者方法定义的代码,编译进主构
造器
//自动把整数转换为分数的隐式转换,隐式转换要起作用,需要定义在作用范围之内。如果你把隐式方法定义放在类
//Rational之内,它就不在解释器的作用范围
implicit def intToRational(x: Int) = new Rational(x)
class Rational(n: Int, d: Int) { //n,d是类参数,只有在本类的方法中可以调用,不能调用其他Rational
require(d != 0) //实例的n,d
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1) //从构造器
def +(that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def +(i: Int): Rational =
new Rational(numer + i * denom, denom)
override def toString = numer+"/"+denom
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
}
for表达式
for {子句} yield {循环体}
for (
file <- filesHere
if file.isFile;
if file.getName.endsWith(".scala")
) yield file
for{
p <- persons //生成器
n = p.name //定义
if(n startsWith "to") //过滤器
} yield n
捕获异常,match表达式
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try {
val f = new FileReader("input.txt")
// Use and close file
} catch {
case ex: FileNotFoundException => // Handle missing file
case ex: IOException => // Handle other I/O error
}
本地函数
import scala.io.Source
object LongLines {
def processFile(filename: String, width: Int) {
def processLine(line: String) {
if (line.length > width)
print(filename +": "+ line)
}
val source = Source.fromFile(filename)
for (line <- source.getLines)
processLine(line)
}
}
函数文本
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.filter((x:Int) => x > 0)
someNumbers.filter(x => x > 0)//短格式,因为someNumbers是List[Int],所以可以省略Int类型
//_占位符,把下划线当做一个或更多参数的占位符,只要每个参数在函数文本内仅出现一次
someNumbers.filter(_ > 0)
偏应用函数:partially applied function
使用一个下划线替换整个参数列表
someNumbers.foreach(println _)
someNumbers.foreach(println)
def sum(a: Int, b: Int, c: Int) = a + b + c
val a = sum _
a(1, 2, 3)
/*名为a的变量指向一个函数值对象。这个函数值是由Scala编译器依照偏应用函数表达式sum _,自动产生的类的一 *个实例。编译器产生的类有一个apply方法带三个参数。之所以带三个参数是因为sum _表达式缺少的参数数量为***三。Scala编译器把表达式a(1,2,3)翻译成对函数值的apply方法的调用,传入三个参数1,2,3。因此*a(1,2,3)是下列代码的短格式:
*/
a.apply(1, 2, 3)
闭包
val more = 1
val addMore = (x:Int) => x + more
函数值是关闭这个开放术语(x: Int) => x + more的行动的最终产物,因此被称为闭包
闭包捕获的是变量本身,不是变量值,所以闭包可以捕获变量本身的改变
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach(sum += _)
someNumbers.foreach((x: Int) => sum = sum + x)
重复参数
def echo(args: String*) = for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)
_*标志告诉编译器把arr的每个元素当做参数,而不是作为单一的参数传给echo
使用函数值和闭包减少代码重复
def filesEnding(query: String) = filesMatching(query, _.endsWith(_))
def filesContaining(query: String) = filesMatching(query, _.contains(_))
def filesRegex(query: String) = filesMatching(query, _.matches(_))
def filesMatching(query: String,
matcher: (String, String) => Boolean) = {
for (file <- filesHere; if matcher(file.getName, query))
yield file
}
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(matcher: String => Boolean) =
for (file <- filesHere; if matcher(file.getName))
yield file
def filesEnding(query: String) = filesMatching(_.endsWith(query))
def filesContaining(query: String) = filesMatching(_.contains(query))
def filesRegex(query: String) = filesMatching(_.matches(query))
}
简化代码
def containsNeg(nums: List[Int]): Boolean = {
var exists = false
for (num <- nums)
if (num < 0)
exists = true
exists
}
def containsNeg(nums: List[Int]) = nums.exists(_ < 0)
curry化
def add(x:Int)(y:Int) = x + y
val second = add(1)_
second(2) //结果是3
second{2} //结果是3,单个参数使用大括号,看上去更像内建控制结构
叫名参数:by-name parameter
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
if (assertionsEnabled && !predicate())
throw new AssertionError
myAssert(() => 5 > 3)//不能使用myAssert(5 > 3)
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
myAssert(5 > 3)
抽象类
abstract class Element {
def contents: Array[String]
//空括号方法,子类可以通过字段和方法来实现
def height = contents.length
def width = if (height == 0) 0 else contents(0).length
}
扩展类 ... extends Element ...
这种extends子句有两个效果:使类ArrayElement从类Element继承所有非私有的成员,并且使ArrayElement成为Element的子类型
class ArrayElement(conts: Array[String]) extends Element {
def contents: Array[String] = conts
}
通常情况下,Scala仅为定义准备了两个命名空间,而Java有四个。Java的四个命名空间是字
段,方法,类型和包。与之相对,Scala的两个命名空间是:
- 值(字段,方法,包还有单例对象)
- 类型(类和特质名)
Scala把字段和方法放进同一个命名空间的理由很清楚,因为这样你就可以使用val重载无参数的
方法,这种你在Java里做不到的事情
协变和逆变
trait Function1[-S, +T]{
def apply(x: S): T
}
class Publication(val title:String)
class Book(title: String) extends Publication(title)
object Library{
val books: Set[Book] =
Set(
new Book("scala book"),
new Book("java book")
)
def printBookList(info: Book => AnyRef){
for (book <- books) println(info(book))
}
}
def getTitle(p: Publication): String = p.title
Library.printBookList(getTitle)
for表达式
for(i <- 1 to 3; from = 4 -i; j <- from to 3) print ((10*i+j + " ")) //13 22 23 31 32 33
for(i <- 1 to 3; from = 4 -i; j <- from to 3 if i != j) yield 10*i+j //scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4)
== equals eq比较
val a = new String("abc")
val b = new String("abc")
a == b //true
a.equals(b) //true
a eq b //false,引用相等
样本类和模式匹配
//1.添加类名工厂方法
case class Test(x:Int)
val a = Test(1) //替代 new Test(1)
//2.将参数列表中的所有隐式参数添加val前缀,当成字段维护
a.x
//3.添加toString,hashCode,equals自然实现
sealed abstract class Expr //封闭类,不能在其他地方定义子类,同时检查模式的穷举性
case class Var(name:String) extends Expr
case class Number(num:Double) extends Expr
case class Unop(operator:String, arg:Expr) extends Expr
case class Binop(operator:String, left:Expr,right:Expr) extends Expr
val op = Binop("+",Number(1.0),Var("x"))
op match {
case Binop(_,Number(1.0),_) => println(op.right)
case _ => println("not match")
}
val op = Unop("abc",Unop("abc",Var("-")))
## 变量绑定
## unchecked,模式穷举性检查被抑制
(op: @unchecked) match {
case Unop("abc", e @ Unop("abc", _)) => e
case _ => println("not match")
}
## option可选类
```scala
1.some(x),x为实际的值;2.None,缺失的值。
val line: Option[String] = None
val a = Map("111" -> "aaa","222" -> "bbb")
def show(x: Option[String]) = x match{
case Some(s) => s
case None => null
}
a.get("111")返回值为Some(value),Some(aaa)// Option[String] = Some(aaa)
a.get("111").orNull返回值或者null
for表达式匹配
val a = List(Some("apple"),None,Some("origin"))
for(Some(fruit) <- a) println(fruit)
list模式匹配
def iSort(xs: List[Int]): List[Int] = xs match{
case List() => List()
case x :: xs1 => insert(x, iSort(xs1))
}
def insert(x:Int, xs: List[Int]): List[Int] = xs match{
case List() => List(x)
case y :: ys => if(x<=y) x::xs else y::insert(x,ys)
}
iSort(List(4,1,3))
列表一阶函数
val a = List(1,2,3)
a.toString //String = List(1, 2, 3)
a.toArray //Array[Int] = Array(1, 2, 3)
a mkString (prfix,sep,posfix)
a.copyToArray(array,len)
"abc".toList //List[Char] = List(a, b, c)
列表高阶函数
xs map f
val words = List("abc","de","g")
words map (_.length) //List(3,2,1)
words flatMap (_.toList) //List[Char] = List(a, b, c, d, e, g)
var sum = 0
List(1,2,3) foreach (sum+=_)//返回类型为Unit, sum=6
List(1,2,3,4) filter (_>2)//List[Int] = List(3, 4)
List(1,2,3,4) partition (_>2)//(List[Int], List[Int]) = (List(3, 4),List(1, 2))
List(1,2,3,0) takeWhile (_>0) //List(1,2,3) 返回列表中最长能满足右操作元的前缀
List(List(1,2,3,0) span (_>0)) //List[(List[Int], List[Int])] = List((List(1, 2, 3),List(0)))
List(1,2,-1) forall (_ > 0) //Boolean = false
List(1,2,-1) exists (_ > 0) //Boolean = true
List(1,4,2) sortWith (_ < _) //List(1, 2, 4)
抽象成员
class test(a:Int,b:Int) //a,b初始化在调用构造函数之前
trait test1{
val a:Int
val b:Int
}
class test2 extends test1{ //抽象成员a,b初始化在构造函数之后
val a = 1
val b = 2
}
//或者下面
new test1{
val a = 1
val b = 2
}
class test3 extends{
val a = 1
val b = 2
}with test1 //预初始化字段,在调用超类之前,trait不像类可以使用类参数初始化
//或者下面
new {
val a = 1
val b = 2
}with test1
抽象类型
class Food
abstract class Animal{
def eat(food:Food)
}
class Grass extends Food
class Cow extends Animal{
def eat(food:Food) = println("Cow eat Grass")
}
class Fish extends Food
(new Cow) eat (new Fish)//正常执行
class Food
abstract class Animal{
type SuitableFood <: Food
def eat(food:SuitableFood)
}
class Grass extends Food
class Cow extends Animal{
type SuitableFood = Grass
def eat(food:Grass) = println("Cow eat Grass")
}
class Fish extends Food
(new Cow) eat (new Fish)//失败
枚举
object color extends Enumeration{
val Red,Green,Blue = Value
}
color.values.foreach(println)
color.Red.id //0
color(0)//Red
隐式转换和参数
隐式转换为期望类型
val a:Int = 3.5 //error
implicit def doubleToInt(x:Double) = x.toInt
val a:Int = 3.5 //3
转换方法接受者
class Rational(n:Int, d:Int){
def +(that:Rational):Rational = ......
def +(that:Int):Rational = ......
}
implicit def intToRational(x:Int) = new Rational(x,1)
1 + (new Rational(2,1))
隐式参数
class PreferredPrompt(val preference:String)
object Greeter{
def greet(name:String)(implicit prompt:PreferredPrompt){
println("welcome," + " name " + ". The system is ready.")
println(prompt.preference)
}
}
object JoesPerfs{
implicit val promptArg = new PreferredPrompt("implict args")
}
import JoesPerfs._
case class StringOrder(a:String) extends Ordered[StringOrder]{
override def compare(that:StringOrder) = this.a.length - that.a.length
}
def maxListUpBond[T <: Ordered[T]](elements:List[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest)
if(x > maxRest) x else maxRest
}
//这个函数的参数不能是List(1,2,3),因为Int类不是Ordered[Int]的子类型
def maxListUpBond[T](elements:List[T])(implicit order:T => Ordered[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest) //相当于maxListUpBond(rest)(order) 作用1:用隐身值补充这个参数
if(x > maxRest) x else maxRest //相当于order(x) > maxRest 作用2:将这个参数当做可用的隐式操作而使用于方法体中
}
//视界 T <% Ordered[T],任何T都好,只要可以被当做Ordered[T]
def maxListUpBond[T <% Ordered[T]](elements:List[T]): T =
elements match{
case List() => throw new RuntimeException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxListUpBond(rest)
if(x > maxRest) x else maxRest
}
scala> def lessThan[T <% Ordered[T]](x : T, y : T) = x < y
lessThan: [T](x: T, y: T)(implicit evidence$1: T => Ordered[T])Boolean
抽取器(extrators)
object Email{
def apply(user:String ,domain:String) = user + "@" + domain
def unapply(str:String): Option[(String,String)] = {
val parts = str split "@"
if(parts.length == 2) Some(parts(0),parts(1)) else None
}
}
val selectorString = Email("163","com")
val selectorString = "test@net"
selectorString match {
case Email(user,domain) => println("user is:"+user+",domain is:"+domain)
}
Email.unapply(selectorString)
object Twice{
def apply(s:String) = s + s
def unapply(s:String): Option[String] = {
val len = s.length/2
val half = s.substring(0,len)
if (half == s.substring(len)) Some(half) else None
}
}
object UpperCase{
def unapply(s:String): Boolean = s.toUpperCase == s
}
def userTwiceUpper(s:String) = s match{
case Email(Twice( x @ UpperCase()),domain) => "user is:"+x+",domain is:"+domain
case _ => None
}
模式守卫
case n:Int if 0 < n => ......
## actor
```scala
import scala.actors._
object SillyActor extends Actor{
def act() {
for (i<- 1 to 5){
println("i is:"+i)
}
}
}
SillyActor.start()
//第二种方式,不需要调用start
import scala.actors.Actor._
val actor2 = actor{
for(i <- 1 to 5) println("i am actor 2")
}
val echoActor = actor{
while(true){
for(i <- 1 to 5) println("i am actor 2")
receive{
case msg => println("received msg:"+msg)
}
}
}
echoActor ! "Hi there"
偏应用函数
val second:List[Int] => Int = {
case x :: y :: _ => y
}
val third:PartialFunction[List[Int],Int] = {
case x::y::_ => y
}
def test1(f:PartialFunction[List[Int],Int]):Nothing = {
val a = List(1,2,3)
println("result is:"+f(a))
throw new RuntimeException("")
}
test1{
case x::y::_ => y
}