scala基础

Scala语法

变量

val a: Int = 3

函数

image
image

函数文本:function literal

函数文本被编译进一个类,类在运行期实例化的时候是一个函数值。函数文本和值的区别在于函数文本存在于源代码,而函数值存在于运行期对象。
都是函数特质trait Function[-S,+T]的实例
args.foreach(arg => println(arg))
函数文本的语法就是,括号里的命名参数列表,右箭头,然后是函数体。语法入下图所示:

image
image

集合

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
}

函数和对象apply

list apply

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容