條件表達式
scala的表達式是有返回值的贴硫,和erlang一樣,語句的最后一個表達式就是返回值
-
可以使用 val s = if (x>0) 1 else -1 的方式聲明變量,此處s 為 Int 類型
- 也可以用 if (x>0) s=1 else s=-1 但前提是先要通過var 聲明 s, 也就是說s就不能是常量了
val s=if(x>0) “asdfadf” else -1 的表達式中英遭,s的類型為Any间护,因為兩個表達式的值類型是不相同的,即混合類型挖诸,那么只能是他們的公共超類Any了
-
if (x>0) 1 則等同于 if (x>0) 1 else ()
() 等同于 java中的void
() 在scala 中的值為Unit汁尺,表示“無值”的值
-
scala終端里需要注意else的換行問題
if (x > 0) 1 else if ( x == 0 ) 0 else -1
需要寫成
if (x > 0) { 1 } else if ( x == 0 ) 0 else -1
在編譯器中編譯時是無需顧慮這個問題的
可以通過:paste 模式將代碼粘貼進去后統(tǒng)一解析執(zhí)行,這樣scala終端就不會近視了
語句終止
-
正常多行時不需要分號税灌,單行有多個表達式時需要分號
- 但是如果不習(xí)慣不使用均函,則可以用,沒什么壞處
-
s=s0+(v-v0)t+ // +告訴解析器這里不是語句的末尾
0.5(a-a0)tt- 這里跟GO很像菱涤,符號放到最后苞也,而不是在新一行的開始
scala推薦左括號在表達式結(jié)尾,而不是新一行的開始
塊表達式和賦值
-
Scala的結(jié)果也是一個表達式粘秆,和其他語言不同如迟,{}的最后一個表達式就是這個塊表達式的值,因此可以使用塊表達式初始化一個值攻走,此特性和Erlang相同
- val distance = { val dx=x0; val dy=y-y0; sqrt(dxdx+dydy**) }
-
Scala的負值動作是沒有值的殷勘,嚴(yán)格來講他的值是Unit
比如 { r=r * n; n -= 1 } 的值是 Unit
不要 x=y=1, 因為 y=1的值是()
輸入和輸出
print
println
printf
readInt
readDouble
readByte
readShort
readLong
readFloat
readBoolean
readChar
-
readLine
- readLine(“Your name:”)
循環(huán)
while(n>0) {}
-
for(i < -1 to n) {}
語法結(jié)構(gòu)可以理解為: for ( i <- 表達式)
1 to n 代表的是1.to(n), 即生成了1 到 n的數(shù)組
<- 代表將后面的表達式的值逐一負值到i,但是這里取決于表達式的類型昔搂,這里是一個Range類型
如果期望表達式的范圍是0到n-1 則可以使用 for( i <- until s.length) {}
-
for (ch <- “hello”)
- 該表達式將字符循環(huán)負值給了ch
-
scala沒有break和continue
一. 使用Boolean型的控制變量
二. 使用嵌套函數(shù) — 你可以從函數(shù)中return
-
三. 使用 Breaks 對象中的 break 方法
import scala.util.control.Breaks._ breakable { for (...) { if (...) break; // 退出breakable塊 ... } }
這種實現(xiàn)其實是在 break 這個語句拋出了一個異常玲销,然后 breakable 塊捕獲異常來實現(xiàn)的
如果對性能要求很高的,應(yīng)該盡量避免使用這套機制
高級for循環(huán)和for推導(dǎo)式
-
通用表達式
-
for (變量1 <- 表達式1 [保護語句1]; [變量定義]…; 變量2 <- 表達式2 [保護語句2]) [yield 表達式]
保護語句格式: if xxxx,
是一個以if 開頭的Boolean 表達式
-
for { 變量1 <- 表達式1 [保護語句1]
[變量定義]
...
變量2 <- 表達式2 [保護語句2] } [yield 表達式]- 可以使用圓括號摘符,分號可以修改為換行
-
-
例子
for(i <- 1 to 3; j <- 1 to 3 if i != j ) print ( ... )
等同于Go語言的
for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { if i != j { fmt.Print(...) } } }
for (i <- 1 to 3; from = 4 - i; j <- from to 3) print(...)
上面在for中定義了變量
for (i <- 1 to 10) yield i % 3
yield表達式贤斜,將生成結(jié)果:Vector(1,2,0,1,2,0,1,2,0,1)
for { i <- 1 to 3 from = 4 - i j <- from to 3 }
函數(shù)
Scala除了方法還支持函數(shù),方法對對象進行操作逛裤,函數(shù)不是
-
def abs(x: Double) = if ( x >= 0) x else -x
必須給出所有參數(shù)的類型
如果函數(shù)比較復(fù)雜瘩绒,則可以使用代碼塊{}, 將代碼放到代碼塊里即可
-
返回參數(shù)
-
如果是非遞歸函數(shù)
- 不需要給出返回類型,Scala編譯器可以通過=符號右側(cè)的表達式的類型推斷出返回類型
-
如果是遞歸函數(shù)
def fac(n: Int): **Int** = if (n <=0) 1 else n * fac(n-1)
-
默認參數(shù)和帶名參數(shù)
-
定義
我們在調(diào)用某些函數(shù)時并不顯示的給出所有的參數(shù)值锁荔,對于這些函數(shù)我們可以使用默認參數(shù)
傳入的參數(shù)如果不帶名字蝙砌,則會按順序?qū)?yīng)到默認參數(shù)里
有時候可以我們只想修改特定的默認參數(shù)择克,而這個參數(shù)又在其他的默認參數(shù)后面祠饺,因此我們需要使用帶名參數(shù)的方法來傳入值
-
例子
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
left參數(shù)和right參數(shù)均有默認值道偷,在調(diào)用的時候如果無特殊需求,則不需要傳入值
帶名參數(shù)的調(diào)用方法def decorate("Hello", right = "]<<<")
變長參數(shù)
-
def sum(args: Int*) = {}
-
調(diào)用方法
val s = sum(1, 4, 9, 16)
val s = sum(1, 4, 9, 16, 25, 100)
-
可以傳入任意數(shù)量的參數(shù)
-
錯誤的使用方法
-
例一
-
錯誤
- val s = sum(1 to 5)
-
正確
-
val s = sum(1 to 5: _*)
-
后面的 :_* 的作用類似Golang的
- sum(numbers …)
-
-
-
-
-
注意
-
當(dāng)你調(diào)用變長參數(shù)且參數(shù)類型為Object的Java方法時并巍,你需要手工對基本類型進行轉(zhuǎn)換
-
例如
-
Java方法
-
MessageFormat public static String format(String pattern, Object... arguments)
- 此處為Java的方法懊渡,且變參的類型為Object
-
-
調(diào)用
var str = MessageFormat.format("The answer to {0} is {1}", "everything", 42.asInstanceOf[AnyRef])
由于42是基本類型剃执,因此需要手動轉(zhuǎn)換到 Scala 的 AnyRef 上肾档,AnyRef 等同于 Java 的 Object
-
-
-
過程
-
定義
如果函數(shù)體包含在花括號當(dāng)中怒见,但沒有前面的 = 號遣耍, 那么返回類型就是Unit炮车,這樣的函數(shù)被稱為 (procedure)
過程不返回值示血,我們調(diào)用它僅僅是為了他的副作用
-
例子
-
我們只是想在屏幕上輸出一段文字
def box(s: String) { … }
大家仔細看难审,這里是沒有等號的,沒有寫成 def box(s: String) = { … }
-
-
習(xí)慣性問題
def box(s: String): Unit = { … }
建議大家總是顯式的聲明Unit返回類型
懶值
-
定義
- 當(dāng)val被聲明為lazy時麸拄,他的初始化將被推遲拢切,直到我們首次對他取值
-
例子
lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString
當(dāng)我們第一次訪問的時候淮椰,這個文件的內(nèi)容才會被讀取,然后復(fù)制給 val
-
對比說明
val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被定義時即被取值 lazy val words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //在words被第一次使用時取值 def words = scala.io.Source.fromFile("/usr/share/dict/words").mkString //words函數(shù)每次被調(diào)用時取值
-
其他說明
- lazy 特性并不是沒有額外開銷泻拦,我們每次訪問都會有一個方法被調(diào)用争拐,而這個方法將會以線程安全的方式檢查該值是否被初始化過
- 有點像Golang里的sync.Once
異常
-
說明
-
受檢異常
scala中無java里的受檢異常特性架曹,即在函數(shù)定義的時候就要指出本函數(shù)將會拋出什么異常绑雄,如果代碼里拋出了未在定義里事先列出的異常夹抗,則在編譯時會報錯
scala的設(shè)計者決定不支持此特性漠烧,因為在編譯期間做徹底的檢查也并不總是好事
-
-
表達式
-
throw 表達式有特殊的類型 Nothing
-
作用
-
if/else
-
if (x > 0) { sqrt (x)
} else throw new IllegalArgumentException("x should not be negative")當(dāng) x > 0 時返回的值是Double
當(dāng) x <=0 時拋出異常已脓,既 Nothing 類型
因此該 if/else 表達式的類型是 Double
-
-
-
-
-
捕獲異常
-
語法
try { … } catch { … }
try { … } finally { … }
作用和異常的拋出規(guī)則類似度液,如果finally 里出了異常,則會覆蓋之前的異常
-
例子
try { process(new URL("http://xxxx.com/yyy.gif")) } catch { case _: MalformedURLException => println("Bad URL:" + url) case ex: IOException => ex.printStackTrace() }
catch 采用的是模式匹配已慢,此例子會將拋出的異常從上到下佑惠,依次對比異常類型膜楷,如果能匹配上則執(zhí)行 => 后面的語句
模式匹配部分類似Go的類型選擇
select v:=Exception.(type) { case MalformedURLException:{ println("Bad URL:" + url) } case IOException:{ v.printStackTrace() } }
-
練習(xí)
-
第一題
def signum(v: Int): Int = { if(v > 0 ){ 1 } else if( v == 0 ){ 0 } else { -1 } }
-
第二題
- 是 Unit赌厅,代表空
-
第三題
-
var x=()
- scala賦值動作本身是沒有值的轿塔,即賦值動作的結(jié)果為Unit,因此 x=y=1, 他的第一步動作是 y=1, 得到 Unit 類型洽议,如果x為Int類型則會報錯亚兄,因此x應(yīng)該為Unit類型
-
-
第四題
for( i<-1 to 10; j=10-i+1) System.out.println(j)
-
第五題
def countdown(n: Int):Unit = { for( i<-1 to n; j=n-i+1) System.out.println(j) }
-
第六題
var value:Long = 1 for(char<- "Hello") value*=char System.out.println(value)
一開始做題時审胚,書上的Hello值為 9415087488, 而我算出來是 825152896膳叨,后來發(fā)現(xiàn)如果 var value = 1 如果不寫類型則是Int型菲嘴,因此是存儲不下的汰翠,要聲明為Long才行
-
此處比較坑爹的是复唤,scala 的解釋器,直接帶入 72101108108111 后算出來的值也是錯的, 還是erlang智能
scala> 72101108108111
res2: Int = 825152896Eshell V8.2 (abort with ^G)
1> 72101108108111.
9415087488
-
第七題
"Hello".foldLeft(1L)(_ * _.toInt)
-
第八題
def product(s: String):Long = { s.foldLeft(1L)(_ * _.toInt) }
-
第九題
def product(s: String,seq: Int = 0, value: Long = 1L):Long = { if(seq>=s.length) value else product(s, seq+1, value*s(seq)) }
-
第十題
def calc(x:Long, n:Long):Long = { if(n>0){ if(n % 2 == 0L){ var y=calc(x,n/2) y*y } else { x*calc(x,n-1) } } else if(n==0){ 1 } else{ 1/calc(x,-n) } }