從java(python)到scala的n種記憶

“大道泛兮,其可左右。
萬(wàn)物恃之而生而不辭,功成不名有。
衣養(yǎng)萬(wàn)物而不為主,常無(wú)欲,可名于小;萬(wàn)物歸焉而不為主,可名為大。
是以圣人之能成大也,以其不為大也,故能成大?!?sup>[1]

本文的出發(fā)點(diǎn)是記錄scala與傳統(tǒng)java以及python的不同之處。

行結(jié)尾方式 抑或 換行符

跟java不同的地方在于,每一行不必以“;”結(jié)尾,除了一個(gè)行如果寫(xiě)多條語(yǔ)句時(shí),前面的語(yǔ)句必須以“;”結(jié)尾。

val rdd = sc.parallelize([1,2,3,4]);println(rdd)

注釋

完全跟java一樣,/**/用于多行;//用于單行。

package

引入包,有兩種方式:

  • 跟java相同
package com.c-goshine.sh.demo;
  • 有些類(lèi)似c#
package com.cgoshine.sh.demo{
  
}

使用這種方式可以在一個(gè)文件中定義個(gè)包。

import

跟python有些像,import可以寫(xiě)在文件的任何地方。
導(dǎo)入某個(gè)包下的所有成員,這個(gè)跟java的方式有些不同,用“_”來(lái)代替java的“*”,如:

import com.cgoshine.sh.demo._ //引入包內(nèi)所有成員

如果想引用包里的幾個(gè)成員,可以使用選擇器selector

import java.awt.{Color, Font}
// 重命名成員
import java.util.{HashMap => JavaHashMap}
// 隱藏成員
import java.util.{HashMap => _, _} // 引入了util包的所有成員,但是HashMap被隱藏了

注意:默認(rèn)情況下,Scala 總會(huì)引入 java.lang._ 、 scala._ 和 Predef._,這里也能解釋?zhuān)瑸槭裁匆詓cala開(kāi)頭的包,在使用時(shí)都是省去scala.的。

數(shù)據(jù)類(lèi)型

scala與java有著相同的數(shù)據(jù)類(lèi)型。

數(shù)據(jù)類(lèi)型 描述
Byte 8位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -128 到 127
Short 16位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -32768 到 32767
Int 32位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -2147483648 到 2147483647
Long 64位有符號(hào)補(bǔ)碼整數(shù)。數(shù)值區(qū)間為 -9223372036854775808 到 9223372036854775807
Float 32位IEEE754單精度浮點(diǎn)數(shù)
Double 64位IEEE754單精度浮點(diǎn)數(shù)
Char 16位無(wú)符號(hào)Unicode字符, 區(qū)間值為 U+0000 到 U+FFFF
String 字符序列
Boolean true或false
Unit 表示無(wú)值,和其他語(yǔ)言中void等同。用作不返回任何結(jié)果的方法的結(jié)果類(lèi)型。Unit只有一個(gè)實(shí)例值,寫(xiě)成()。
Null null 或空引用
Nothing Nothing類(lèi)型在Scala的類(lèi)層級(jí)的最低端;它是任何其他類(lèi)型的子類(lèi)型。
Any Any是所有其他類(lèi)的超類(lèi)
AnyRef AnyRef類(lèi)是Scala里所有引用類(lèi)(reference class)的基類(lèi)

變量聲明

用var聲明變量;用val聲明常量

格式:var VariableName : DataType [= Initial Value]

var ss:String [="rzaor"]
var ss //裸奔方式

訪問(wèn)修飾符

public private protected

  • private
    默認(rèn)public,其中private比java要嚴(yán)格(在嵌套類(lèi)情況下,外層類(lèi)甚至不能訪問(wèn)被嵌套類(lèi)的私有成員)。
class Outer{
    class Inner{
    private def f(){println("f")}
    class InnerMost{
        f() // 正確
        }
    }
    (new Inner).f() //錯(cuò)誤
}
  • protected
    同樣也比java的要嚴(yán)格。因?yàn)樗辉试S保護(hù)成員在定義了該成員的的類(lèi)的子類(lèi)中被訪問(wèn)。而在java中,用protected關(guān)鍵字修飾的成員,除了定義了該成員的類(lèi)的子類(lèi)可以訪問(wèn),同一個(gè)包里的其他類(lèi)也可以進(jìn)行訪問(wèn)。
package p{
class Super{
    protected def f() {println("f")}
    }
    class Sub extends Super{
        f()
    }
    class Other{
        (new Super).f() //錯(cuò)誤
    }
}
  • 作用域保護(hù)
private[x]
protected[x]

理解為:如果寫(xiě)成private[x],讀作"這個(gè)成員除了對(duì)[…]中的類(lèi)或[…]中的包中的類(lèi)及它們的伴生對(duì)像可見(jiàn)外,對(duì)其它所有類(lèi)都是private。這種技巧在橫跨了若干包的大型項(xiàng)目中非常有用,它允許你定義一些在你項(xiàng)目的若干子包中可見(jiàn)但對(duì)于項(xiàng)目外部的客戶(hù)卻始終不可見(jiàn)的東西。

package bobsrocckets{
    package navigation{
        private[bobsrockets] class Navigator{
         protected[navigation] def useStarChart(){}
         class LegOfJourney{
             private[Navigator] val distance = 100
             }
            private[this] var speed = 200
            }
        }
        package launch{
        import navigation._
        object Vehicle{
        private[launch] val guide = new Navigator
        }
    }
}

類(lèi)Navigator被標(biāo)記為private[bobsrockets]就是說(shuō)這個(gè)類(lèi)對(duì)包含在bobsrockets包里的所有的類(lèi)和對(duì)象可見(jiàn)。
比如說(shuō),從Vehicle對(duì)象里對(duì)Navigator的訪問(wèn)是被允許的,因?yàn)閷?duì)象Vehicle包含在包launch中,而launch包在bobsrockets中,相反,所有在包bobsrockets之外的代碼都不能訪問(wèn)類(lèi)Navigator。

位運(yùn)算符

位運(yùn)算符用來(lái)對(duì)二進(jìn)制位進(jìn)行操作,~,&,|,^分別為取反,按位與與,按位與或,按位與異或運(yùn)算。
如果指定 A = 60; 及 B = 13; 兩個(gè)變量對(duì)應(yīng)的二進(jìn)制為:

A = 0011 1100

B = 0000 1101

-------位運(yùn)算----------

A&B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

~A  = 1100 0011

Scala 中的按位運(yùn)算法則如下:

運(yùn)算符 描述 實(shí)例
& 按位與運(yùn)算符 (a & b) 輸出結(jié)果 12 ,二進(jìn)制解釋?zhuān)?0000 1100
| 按位或運(yùn)算符 (a | b) 輸出結(jié)果 61 ,二進(jìn)制解釋?zhuān)?0011 1101
^ 按位異或運(yùn)算符 (a ^ b) 輸出結(jié)果 49 ,二進(jìn)制解釋?zhuān)?0011 0001
~ 按位取反運(yùn)算符 (~a ) 輸出結(jié)果 -61 ,二進(jìn)制解釋?zhuān)?1100 0011, 在一個(gè)有符號(hào)二進(jìn)制數(shù)的補(bǔ)碼形式。
<< 左移動(dòng)運(yùn)算符 a << 2 輸出結(jié)果 240 ,二進(jìn)制解釋?zhuān)?1111 0000
>> 右移動(dòng)運(yùn)算符 a >> 2 輸出結(jié)果 15 ,二進(jìn)制解釋?zhuān)?0000 1111
>>> 無(wú)符號(hào)右移 A >>>2 輸出結(jié)果 15, 二進(jìn)制解釋: 0000 1111

函數(shù) 方法

Scala 有函數(shù)和方法,二者在語(yǔ)義上的區(qū)別很小。Scala 方法是類(lèi)的一部分,而函數(shù)是一個(gè)對(duì)象可以賦值給一個(gè)變量。換句話(huà)來(lái)說(shuō)在類(lèi)中定義的函數(shù)即是方法。

  • 函數(shù)聲明
def functionName ([參數(shù)列表]) : [return type]
  • 函數(shù)定義
def functionName ([參數(shù)列表]) : [return type] = {
   function body
   return [expr]
}

如果函數(shù)沒(méi)有返回值,可以返回為 Unit,這個(gè)類(lèi)似于 Java 的 void。

object add{
   def addInt( a:Int, b:Int ) : Int = {
      var sum:Int = 0
      sum = a + b
      return sum
   }
  def printMe( ) : Unit = {
      println("Hello, Scala!")
   }
}

閉包

閉包是一個(gè)函數(shù),返回值依賴(lài)于聲明在函數(shù)外部的一個(gè)或多個(gè)變量。
如下面這段匿名的函數(shù):

val multiplier = (i:Int) => i * 10  

函數(shù)體內(nèi)有一個(gè)變量 i,它作為函數(shù)的一個(gè)參數(shù)。如下面的另一段代碼:

val multiplier = (i:Int) => i * factor

在 multiplier 中有兩個(gè)變量:i 和 factor。其中的一個(gè) i 是函數(shù)的形式參數(shù),在 multiplier 函數(shù)被調(diào)用時(shí),i 被賦予一個(gè)新的值。然而,factor不是形式參數(shù),而是自由變量,考慮下面代碼:

var factor = 3  
val multiplier = (i:Int) => i * factor  

這樣定義的函數(shù)變量 multiplier 成為一個(gè)"閉包",因?yàn)樗玫胶瘮?shù)外面定義的變量,定義這個(gè)函數(shù)的過(guò)程是將這個(gè)自由變量捕獲而構(gòu)成一個(gè)封閉的函數(shù)。

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  
}  

函數(shù)的閉包就是當(dāng)函數(shù)的參數(shù)超出其作用域時(shí),我們還能對(duì)參數(shù)進(jìn)行訪問(wèn)。

scala> def iscala(content:String) = (message:String) => println(content + " "+ message)
iscala: (content: String)String => Unit

scala> val func1 = iscala("spark")
func1: String => Unit = $$Lambda$1228/248295195@3dceec83

scala> func1("hadoop")
spark hadoop

scala> func1("hbase")
spark hbase

在調(diào)用func1時(shí),將之前的content參數(shù)的值延續(xù)了下來(lái)。

字符串連接

string1.concat(string2);

同樣你也可以使用加號(hào)(+)來(lái)連接

  • 創(chuàng)建格式化字符串
object Test {
   def main(args: Array[String]) {
      var floatVar = 12.456
      var intVar = 2000
      var stringVar = "scala multi-paradigm!"
      var fs = printf("浮點(diǎn)型變量為 " +
                   "%f, 整型變量為 %d, 字符串為 " +
                   " %s", floatVar, intVar, stringVar)
      println(fs)
   }
}

for循環(huán)

for( var x <- Range ){
   statement(s);
}

Range 可以是一個(gè)數(shù)字區(qū)間表示 i to j ,或者 i until j。左箭頭 <- 用于為變量 x 賦值。
舉個(gè)例子:

object Test {
   def main(args: Array[String]) {
      var a = 0;
      // for 循環(huán)
      for( a <- 1 to 10){
         println( "Value of a: " + a );
      }
   }
}

類(lèi)和對(duì)象

Scala中的類(lèi)不聲明為public,一個(gè)Scala源文件中可以有多個(gè)類(lèi)。

class Point(xc: Int, yc: Int) {
  ……
}

繼承

Scala繼承一個(gè)基類(lèi)跟Java很相似, 但我們需要注意以下幾點(diǎn):

  • 重寫(xiě)一個(gè)非抽象方法必須使用override修飾符。
  • 只有主構(gòu)造函數(shù)才可以往基類(lèi)的構(gòu)造函數(shù)里寫(xiě)參數(shù)。
  • 在子類(lèi)中重寫(xiě)超類(lèi)的抽象方法時(shí),你不需要使用override關(guān)鍵字。

繼承會(huì)繼承父類(lèi)的所有屬性和方法,Scala 只允許繼承一個(gè)父類(lèi)。

單例對(duì)象 & 伴生對(duì)象

Scala單例對(duì)象是十分重要的,不像Java一樣,有靜態(tài)類(lèi)、靜態(tài)成員、靜態(tài)方法,但是Scala提供了object對(duì)象,這個(gè)object對(duì)象類(lèi)似于Java的靜態(tài)類(lèi),它的成員、它的方法都默認(rèn)是靜態(tài)的。
如果object的靜態(tài)成員要被外界訪問(wèn),則該成員不能被private修飾。
伴生對(duì)象首先是一個(gè)單例對(duì)象,單例對(duì)象用關(guān)鍵字object定義。在Scala中,單例對(duì)象分為兩種,一種是并未自動(dòng)關(guān)聯(lián)到特定類(lèi)上的單例對(duì)象,稱(chēng)為獨(dú)立對(duì)象 (Standalone Object);另一種是關(guān)聯(lián)到一個(gè)類(lèi)上的單例對(duì)象,該單例對(duì)象與該類(lèi)共有相同名字,則這種單例對(duì)象稱(chēng)為伴生對(duì)象(Companion Object),對(duì)應(yīng)類(lèi)稱(chēng)為伴生類(lèi)。

Trait(特性)

Scala Trait(特征) 相當(dāng)于 Java 的接口,實(shí)際上它比接口還功能強(qiáng)大。
與接口不同的是,它還可以定義屬性和方法的實(shí)現(xiàn)。
一般情況下Scala的類(lèi)只能夠繼承單一父類(lèi),但是如果是 Trait(特征) 的話(huà)就可以繼承多個(gè),從結(jié)果來(lái)看就是實(shí)現(xiàn)了多重繼承。
Trait(特征) 定義的方式與類(lèi)類(lèi)似,但它使用的關(guān)鍵字是 trait。

package com.cgoshine.sh.demo.scala

trait Equal {
  def isEqual(x:Any):Boolean
  def isNotEqual(x:Any):Boolean = !isEqual(x)
}

isEqual 方法沒(méi)有定義方法的實(shí)現(xiàn),isNotEqual定義了方法的實(shí)現(xiàn)。子類(lèi)繼承特征可以實(shí)現(xiàn)未被實(shí)現(xiàn)的方法。所以其實(shí) Scala Trait(特征)更像 Java 的抽象類(lèi)。

implements這個(gè)在scala中到目前為止還沒(méi)見(jiàn)到,即使“實(shí)現(xiàn)”Trait中也是用的extends。

class Point(xc: Int, yc: Int) extends Equal {
……
}

模式匹配

Scala 提供了強(qiáng)大的模式匹配機(jī)制,應(yīng)用也非常廣泛。
match 對(duì)應(yīng) Java 里的 switch,但是寫(xiě)在選擇器表達(dá)式之后。即: 選擇器 match {備選項(xiàng)}。
一個(gè)模式匹配包含了一系列備選項(xiàng),每個(gè)都開(kāi)始于關(guān)鍵字 case。每個(gè)備選項(xiàng)都包含了一個(gè)模式及一到多個(gè)表達(dá)式。箭頭符號(hào) => 隔開(kāi)了模式和表達(dá)式。

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

   }
   def matchTest(x: Int): String = x match {
      case 1 => "one"
      case 2 => "two"
      case _ => "many"
   }
}

“_”,默認(rèn)的全匹配備選項(xiàng),即沒(méi)有找到其他匹配時(shí)的匹配項(xiàng),類(lèi)似 switch 中的 default。

  • 使用樣例類(lèi)
    使用了case關(guān)鍵字的類(lèi)定義就是就是樣例類(lèi)(case classes),樣例類(lèi)是種特殊的類(lèi),經(jīng)過(guò)優(yōu)化以用于模式匹配。
object Test {
   def main(args: Array[String]) {
       val alice = new Person("Alice", 25)
    val bob = new Person("Bob", 32)
       val charlie = new Person("Charlie", 32)
   
    for (person <- List(alice, bob, charlie)) {
        person match {
            case Person("Alice", 25) => println("Hi Alice!")
            case Person("Bob", 32) => println("Hi Bob!")
            case Person(name, age) =>
               println("Age: " + age + " year, name: " + name + "?")
         }
      }
   }
   // 樣例類(lèi)
   case class Person(name: String, age: Int)
}

在聲明樣例類(lèi)時(shí),下面的過(guò)程自動(dòng)發(fā)生了:

構(gòu)造器的每個(gè)參數(shù)都成為val,除非顯式被聲明為var,但是并不推薦這么做;
在伴生對(duì)象中提供了apply方法,所以可以不使用new關(guān)鍵字就可構(gòu)建對(duì)象;
提供unapply方法使模式匹配可以工作;
生成toString、equals、hashCode和copy方法,除非顯示給出這些方法的定義。

正則表達(dá)式

Scala 通過(guò) scala.util.matching 包中的 Regex 類(lèi)來(lái)支持正則表達(dá)式。

import scala.util.matching.Regex

object Test {
   def main(args: Array[String]) {
      val pattern = "Scala".r
      val str = "Scala is Scalable and cool"
      
      println(pattern findFirstIn str)
   }
}

使用 String 類(lèi)的 r() 方法構(gòu)造了一個(gè)Regex對(duì)象,然后使用 findFirstIn 方法找到首個(gè)匹配項(xiàng)。
如果需要查看所有的匹配項(xiàng)可以使用 findAllIn 方法。你可以使用 mkString( ) 方法來(lái)連接正則表達(dá)式匹配結(jié)果的字符串,并可以使用管道(|)來(lái)設(shè)置不同的模式:

import scala.util.matching.Regex

object Test {
   def main(args: Array[String]) {
      val pattern = new Regex("(S|s)cala")  // 首字母可以是大寫(xiě) S 或小寫(xiě) s
      val str = "Scala is scalable and cool"
      
      println((pattern findAllIn str).mkString(","))   // 使用逗號(hào) , 連接返回結(jié)果
   }
}

輸出結(jié)果為:

$ scalac Test.scala 
$ scala Test
Scala,scala

如果你需要將匹配的文本替換為指定的關(guān)鍵詞,可以使用 replaceFirstIn( ) 方法來(lái)替換第一個(gè)匹配項(xiàng),使用 replaceAllIn( ) 方法替換所有匹配項(xiàng)。

object Test {
   def main(args: Array[String]) {
      val pattern = "(S|s)cala".r
      val str = "Scala is scalable and cool"
      
      println(pattern replaceFirstIn(str, "Java"))
   }
}

Scala 的正則表達(dá)式繼承了 Java 的語(yǔ)法規(guī)則,Java 則大部分使用了 Perl 語(yǔ)言的規(guī)則。

  • 規(guī)則:
表達(dá)式 匹配規(guī)則
^ 匹配輸入字符串開(kāi)始的位置。
$ 匹配輸入字符串結(jié)尾的位置。
. 匹配除"\r\n"之外的任何單個(gè)字符。
[...] 字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。
[^...] 反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。
\A 匹配輸入字符串開(kāi)始的位置(無(wú)多行支持)
\z 字符串結(jié)尾(類(lèi)似$,但不受處理多行選項(xiàng)的影響)
\Z 字符串結(jié)尾或行尾(不受處理多行選項(xiàng)的影響)
re* 重復(fù)零次或更多次
re+ 重復(fù)一次或更多次
re? 重復(fù)零次或一次
re{ n} 重復(fù)n次
re{ n,}
re{ n, m} 重復(fù)n到m次
a|b 匹配 a 或者 b
(re) 匹配 re,并捕獲文本到自動(dòng)命名的組里
(?: re) 匹配 re,不捕獲匹配的文本,也不給此分組分配組號(hào)
(?> re) 貪婪子表達(dá)式
\w 匹配字母或數(shù)字或下劃線或漢字
\W 匹配任意不是字母,數(shù)字,下劃線,漢字的字符
\s 匹配任意的空白符,相等于 [\t\n\r\f]
\S 匹配任意不是空白符的字符
\d 匹配數(shù)字,類(lèi)似 [0-9]
\D 匹配任意非數(shù)字的字符
\G 當(dāng)前搜索的開(kāi)頭
\n 換行符
\b 通常是單詞分界位置,但如果在字符類(lèi)里使用代表退格
\B 匹配不是單詞開(kāi)頭或結(jié)束的位置
\t 制表符
\Q 開(kāi)始引號(hào):\Q(a+b)3\E 可匹配文本 "(a+b)3"。
\E 結(jié)束引號(hào):\Q(a+b)3\E 可匹配文本 "(a+b)3"。
  • 實(shí)例:
實(shí)例 描述
. 匹配除"\r\n"之外的任何單個(gè)字符。
[Rr]uby 匹配 "Ruby" 或 "ruby"
rub[ye] 匹配 "ruby" 或 "rube"
[aeiou] 匹配小寫(xiě)字母 :aeiou
[0-9] 匹配任何數(shù)字,類(lèi)似 [0123456789]
[a-z] 匹配任何 ASCII 小寫(xiě)字母
[A-Z] 匹配任何 ASCII 大寫(xiě)字母
[a-zA-Z0-9] 匹配數(shù)字,大小寫(xiě)字母
[^aeiou] 匹配除了 aeiou 其他字符
[^0-9] 匹配除了數(shù)字的其他字符
\d 匹配數(shù)字,類(lèi)似: [0-9]
\D 匹配非數(shù)字,類(lèi)似: [^0-9]
\s 匹配空格,類(lèi)似: [ \t\r\n\f]
\S 匹配非空格,類(lèi)似: [^ \t\r\n\f]
\w 匹配字母,數(shù)字,下劃線,類(lèi)似: [A-Za-z0-9_]
\W 匹配非字母,數(shù)字,下劃線,類(lèi)似: [^A-Za-z0-9_]
ruby? 匹配 "rub" 或 "ruby": y 是可選的
ruby* 匹配 "rub" 加上 0 個(gè)或多個(gè)的 y。
ruby+ 匹配 "rub" 加上 1 個(gè)或多個(gè)的 y。
\d{3} 剛好匹配 3 個(gè)數(shù)字。
\d{3,} 匹配 3 個(gè)或多個(gè)數(shù)字。
\d{3,5} 匹配 3 個(gè)、4 個(gè)或 5 個(gè)數(shù)字。
\D\d+ 無(wú)分組: + 重復(fù) \d
(\D\d)+/ 分組: + 重復(fù) \D\d 對(duì)
([Rr]uby(, )?)+ 匹配 "Ruby"、"Ruby, ruby, ruby",等等

異常處理

Scala 的異常處理和其它語(yǔ)言比如 Java 類(lèi)似。

throw new FileNotFoundException

如果有異常發(fā)生,catch字句是按次序捕捉的。因此,在catch字句中,越具體的異常越要靠前,越普遍的異常越靠后。 如果拋出的異常不在catch字句中,該異常則無(wú)法處理,會(huì)被升級(jí)到調(diào)用者處。
捕捉異常的catch子句,語(yǔ)法與其他語(yǔ)言中不太一樣。在Scala里,借用了模式匹配的思想來(lái)做異常的匹配,因此,在catch的代碼里,是一系列case字句:

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException =>{
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      }
   }
}
  • finally 語(yǔ)句
    finally 語(yǔ)句用于執(zhí)行不管是正常處理還是有異常發(fā)生時(shí)都需要執(zhí)行的步驟。
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object Test {
   def main(args: Array[String]) {
      try {
         val f = new FileReader("input.txt")
      } catch {
         case ex: FileNotFoundException => {
            println("Missing file exception")
         }
         case ex: IOException => {
            println("IO Exception")
         }
      } finally {
         println("Exiting finally...")
      }
   }
}

提取器(Extractor)

提取器是從傳遞給它的對(duì)象中提取出構(gòu)造該對(duì)象的參數(shù)。
Scala 提取器是一個(gè)帶有unapply方法的對(duì)象。unapply方法算是apply方法的反向操作:unapply接受一個(gè)對(duì)象,然后從對(duì)象中提取值,提取的值通常是用來(lái)構(gòu)造該對(duì)象的值。

object Test {
   def main(args: Array[String]) {
      
      println ("Apply 方法 : " + apply("Zara", "gmail.com"));
      println ("Unapply 方法 : " + unapply("Zara@gmail.com"));
      println ("Unapply 方法 : " + unapply("Zara Ali"));

   }
   // 注入方法 (可選)
   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
      }
   }
}

輸出:

$ scalac Test.scala 
$ scala Test
Apply 方法 : Zara@gmail.com
Unapply 方法 : Some((Zara,gmail.com))
Unapply 方法 : None

Options Some None

Some和None都是Options的子類(lèi),Scala鼓勵(lì)你在變量和函數(shù)返回值可能不會(huì)引用任何值的時(shí)候使用Option類(lèi)型。在沒(méi)有值的時(shí)候,使用None;如果有值可以引用,就使用Some來(lái)包含這個(gè)值。

scala> val capitals = Map("France"->"Paris", "Japan"->"Tokyo", "China"->"Beijing")
capitals: scala.collection.immutable.Map[String,String] = Map(France -> Paris, Japan -> Tokyo, China -> Beijing)

scala> capitals get "France"
res0: Option[String] = Some(Paris)

scala> capitals get "Germany"
res1: Option[String] = None

當(dāng)程序回傳Some的時(shí)候,代表函式返回一個(gè)String,你可以調(diào)用get()函數(shù)獲得那個(gè)String,如果程序返回的是None,則代表沒(méi)有字符串可以給你。
在返回None,也就是沒(méi)有String給你的時(shí)候,如果你還硬要調(diào)用get()來(lái)取得 String 的話(huà),Scala一樣是會(huì)拋出一個(gè)NoSuchElementException異常給你的。
我們也可以選用另外一個(gè)方法,getOrElse。這個(gè)方法在這個(gè)Option是Some的實(shí)例時(shí)返回對(duì)應(yīng)的值,而在是None的實(shí)例時(shí)返回傳入的參數(shù)。換句話(huà)說(shuō),傳入getOrElse的參數(shù)實(shí)際上是默認(rèn)返回值。

scala> capitals get "Germany" get
warning: there was one feature warning; re-run with -feature for details
java.util.NoSuchElementException: None.get
  ……

scala> capitals get "France" get
warning: there was one feature warning; re-run with -feature for details
res3: String = Paris

scala> (capitals get "Germany") getOrElse "Oops"
res7: String = Oops

scala> capitals get "France" getOrElse "Oops"
res8: String = Paris

文件 I/O

Scala 進(jìn)行文件寫(xiě)操作,直接用的都是 java中 的 I/O 類(lèi) (java.io.File):

import java.io._

object Test {
   def main(args: Array[String]) {
      val writer = new PrintWriter(new File("demo.txt" ))

      writer.write("com.cgoshine.sh.demo")
      writer.close()
   }
}
  • 從屏幕讀取輸入
object Test {
   def main(args: Array[String]) {
      print("input your company's name : " )
      val line = Console.readLine
      
      println("thanks,your input is: " + line)
   }
}
  • 從文件讀取
    從文件讀取內(nèi)容非常簡(jiǎn)單。我們可以使用 Scala 的 Source 類(lèi)及伴生對(duì)象來(lái)讀取文件。
import scala.io.Source

object Test {
   def main(args: Array[String]) {
      println("文件內(nèi)容為:" )

      Source.fromFile("test.txt" ).foreach{ 
         print 
      }
   }
}

  1. 老子《道德經(jīng)》第三十四章,老子故里,中國(guó)鹿邑。 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容