scala基礎(chǔ)

Scala語法

變量

val a: Int = 3

函數(shù)

image
image

函數(shù)文本:function literal

函數(shù)文本被編譯進一個類筑舅,類在運行期實例化的時候是一個函數(shù)值摊唇。函數(shù)文本和值的區(qū)別在于函數(shù)文本存在于源代碼烹俗,而函數(shù)值存在于運行期對象呀酸。
都是函數(shù)特質(zhì)trait Function[-S,+T]的實例
args.foreach(arg => println(arg))
函數(shù)文本的語法就是次酌,括號里的命名參數(shù)列表酣栈,右箭頭,然后是函數(shù)體。語法入下圖所示:

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"這樣的二元操作符表達式轉(zhuǎn)換為(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

函數(shù)式對象 對象狀態(tài)不可改變

Scala編譯器將把你放在類內(nèi)部的任何不是字段的部分或者方法定義的代碼蛉顽,編譯進主構(gòu)
造器

//自動把整數(shù)轉(zhuǎn)換為分數(shù)的隱式轉(zhuǎn)換,隱式轉(zhuǎn)換要起作用斜纪,需要定義在作用范圍之內(nèi)鸟悴。如果你把隱式方法定義放在類
//Rational之內(nèi)徘铝,它就不在解釋器的作用范圍
implicit def intToRational(x: Int) = new Rational(x)
class Rational(n: Int, d: Int) {   //n,d是類參數(shù)耳胎,只有在本類的方法中可以調(diào)用,不能調(diào)用其他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) //從構(gòu)造器  
  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 {循環(huán)體}

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
}  

本地函數(shù)

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)
  }
}

函數(shù)文本

val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.filter((x:Int) => x > 0)
someNumbers.filter(x => x > 0)//短格式怕午,因為someNumbers是List[Int],所以可以省略Int類型
//_占位符淹魄,把下劃線當做一個或更多參數(shù)的占位符郁惜,只要每個參數(shù)在函數(shù)文本內(nèi)僅出現(xiàn)一次
someNumbers.filter(_ > 0)    

偏應(yīng)用函數(shù):partially applied function

使用一個下劃線替換整個參數(shù)列表

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的變量指向一個函數(shù)值對象。這個函數(shù)值是由Scala編譯器依照偏應(yīng)用函數(shù)表達式sum _甲锡,自動產(chǎn)生的類的一 *個實例兆蕉。編譯器產(chǎn)生的類有一個apply方法帶三個參數(shù)。之所以帶三個參數(shù)是因為sum _表達式缺少的參數(shù)數(shù)量為***三缤沦。Scala編譯器把表達式a(1,2,3)翻譯成對函數(shù)值的apply方法的調(diào)用虎韵,傳入三個參數(shù)1,2缸废,3包蓝。因此*a(1,2,3)是下列代碼的短格式:
*/
a.apply(1, 2, 3)

閉包

val more = 1
val addMore = (x:Int) => x + more 

函數(shù)值是關(guān)閉這個開放術(shù)語(x: Int) => x + more的行動的最終產(chǎn)物,因此被稱為閉包
閉包捕獲的是變量本身企量,不是變量值测萎,所以閉包可以捕獲變量本身的改變

val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach(sum += _)
someNumbers.foreach((x: Int) => sum = sum + x)

重復(fù)參數(shù)

def echo(args: String*) = for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)

_*標志告訴編譯器把arr的每個元素當做參數(shù),而不是作為單一的參數(shù)傳給echo

使用函數(shù)值和閉包減少代碼重復(fù)

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) //結(jié)果是3
second{2} //結(jié)果是3届巩,單個參數(shù)使用大括號硅瞧,看上去更像內(nèi)建控制結(jié)構(gòu)

叫名參數(shù):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]
  //空括號方法,子類可以通過字段和方法來實現(xiàn)
  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的兩個命名空間是:

  • 值(字段,方法蟀架,包還有單例對象)
  • 類型(類和特質(zhì)名)

Scala把字段和方法放進同一個命名空間的理由很清楚瓣赂,因為這樣你就可以使用val重載無參數(shù)的
方法榆骚,這種你在Java里做不到的事情

協(xié)變和逆變

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.將參數(shù)列表中的所有隱式參數(shù)添加val前綴煌集,當成字段維護
a.x
//3.添加toString,hashCode,equals自然實現(xiàn)
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))

列表一階函數(shù)

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)

列表高階函數(shù)

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初始化在調(diào)用構(gòu)造函數(shù)之前
trait test1{
  val a:Int
  val b:Int
}
class test2 extends test1{  //抽象成員a,b初始化在構(gòu)造函數(shù)之后
  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 //預(yù)初始化字段喊废,在調(diào)用超類之前,trait不像類可以使用類參數(shù)初始化
//或者下面
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)//正常執(zhí)行

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  

隱式轉(zhuǎn)換和參數(shù)

隱式轉(zhuǎn)換為期望類型

val a:Int = 3.5 //error
implicit def doubleToInt(x:Double) = x.toInt
val a:Int = 3.5 //3

轉(zhuǎn)換方法接受者

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))

隱式參數(shù)

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
}
//這個函數(shù)的參數(shù)不能是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:用隱身值補充這個參數(shù)
      if(x > maxRest) x else maxRest    //相當于order(x) > maxRest      作用2:將這個參數(shù)當做可用的隱式操作而使用于方法體中
}
//視界 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
}

模式守衛(wèi)

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()
//第二種方式,不需要調(diào)用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"

偏應(yīng)用函數(shù)

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
}

函數(shù)和對象apply

list apply

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揪惦,一起剝皮案震驚了整個濱河市罗侯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纫塌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讲弄,死亡現(xiàn)場離奇詭異措左,居然都是意外死亡,警方通過查閱死者的電腦和手機避除,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門怎披,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓶摆,你說我怎么就攤上這事凉逛。” “怎么了群井?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵状飞,是天一觀的道長。 經(jīng)常有香客問我,道長诬辈,這世上最難降的妖魔是什么酵使? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮焙糟,結(jié)果婚禮上口渔,老公的妹妹穿的比我還像新娘。我一直安慰自己穿撮,他們只是感情好缺脉,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布枪向。 她就那樣靜靜地躺著,像睡著了一般傍衡。 火紅的嫁衣襯著肌膚如雪倦畅。 梳的紋絲不亂的頭發(fā)上叠赐,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機與錄音罢洲,去河邊找鬼惹苗。 笑死桩蓉,一個胖子當著我的面吹牛帚戳,可吹牛的內(nèi)容都是我干的儡首。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼氛濒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了窿冯?” 一聲冷哼從身側(cè)響起执桌,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缠沈,沒想到半個月后颓芭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畜伐,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年慎框,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馅精。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡漫玄,死狀恐怖睦优,靈堂內(nèi)的尸體忽然破棺而出汗盘,到底是詐尸還是另有隱情隐孽,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布送粱,位于F島的核電站,受9級特大地震影響动雹,放射性物質(zhì)發(fā)生泄漏胰蝠。R本人自食惡果不足惜茸塞,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望效扫。 院中可真熱鬧,春花似錦浩习、人聲如沸瘦锹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塔拳。三九已至靠抑,卻和暖如春颂碧,著一層夾襖步出監(jiān)牢的瞬間载城,已是汗流浹背诉瓦。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猴贰,地道東北人米绕。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓迈套,卻偏偏與公主長得像桑李,于是被迫代替她去往敵國和親贵白。 傳聞我的和親對象是個殘疾皇子禁荒,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容