scalac 與 fsc


你可以在一個純文字檔案中撰寫程式碼,然後使用 scala 指令 直譯為位元組(byte code)後運行於JVM之上。你也可以撰寫程式碼,使用scalac指令將程式碼編譯為.class檔案,而後使用scala指令來執行。如果你要這麼作,則要定義object,並撰寫程式進入點,例如:
  • Hello.scala
object Hello {
def main(args: Array[String]) {
println("Hello!" + args(0) + "!")
}
}

object在Scala中用來定義單例物件(Singleton object),技術上來說,在程式運行時,Hello名稱實際是參考至Hello\$類別的物件,不過就現階段而言,你還不用深入了解,你只要先記得,Scala程式要編譯為位元碼後,若要提供JVM執行程式的程式進入點,必須使用以上的形式。def定義了一個main方法,函式中args是個參考名稱,型態是字串陣列(Array[String]),用來收集執行程式時所提供的命令列引數。

要注意的是,表面上看來,雖然上面這個程式有點像是在Java中定義主類別以及一個static的main程式進入點,不過這並不正確,Scala並沒有static定義的語法。

程式的檔案名稱可以命名為Hello.scala,不過也可以取其它的名稱,慣例上會使用與object名稱或class名稱相同的檔案名稱,如此別人可以很方便地找到原始碼進行檢視。

要編譯這個程式碼,可以使用以下的指令:
>scalac Hello.scala

這會在你的指令執行路徑下產生編譯好的.class檔案,若要執行,則可以使用scala指令,例如:
>scala Hello caterpillar
Hello!caterpillar!


Scala程式碼是編譯為.class,也是運行於JVM之上,所以實際上,你也可以使用JDK的java指令來運行,不過必須在 Classpath中包括Scala的程式碼scala-library.jar,這是位於Scala安裝目錄lib目錄中,一個執行簵例如下:
>java -cp .;C:\Greenware\scala-2.7.7\lib\scala-library.jar Hello caterpillar
Hello!caterpillar!


想要知道scalac有哪些選項可以使用,可以使用-help引數,大多數的引數與javac的引數作用是相同的:
>C:\workspace>scalac -help
Usage: scalac <options> <source files>
where possible standard options include:
  -g:<g>                       Specify level of generated debugging info (none,source,line,vars,notailcalls)
  -nowarn                      Generate no warnings
  -verbose                     Output messages about what the compiler is doing
  -deprecation                 Output source locations where deprecated APIs are used
  -unchecked                   Enable detailed unchecked warnings
  -classpath <path>            Specify where to find user class files
  -sourcepath <path>           Specify where to find input source files
  -bootclasspath <path>        Override location of bootstrap class files
  -extdirs <dirs>              Override location of installed extensions
  -d <directory>               Specify where to place generated class files
  -encoding <encoding>         Specify character encoding used by source files
  -target:<target>             Specify for which target object files should be built (jvm-1.5,jvm-1.4,msil)
  -print                       Print program with all Scala-specific features removed
  -optimise                    Generates faster bytecode by applying optimisations to the program
  -explaintypes                Explain type errors in more detail
  -uniqid                      Print identifiers with unique names for debugging
  -version                     Print product version and exit
  -help                        Print a synopsis of standard options
  -X                           Print a synopsis of advanced options
  @<file>                      A text file containing compiler arguments (options and source files)


每次啟動scalac指令,都必須掃描所有使用到的JAR檔案內容,並作一些初始化的動作,接著才是真正編譯程式碼。Scala提供了一個fsc指令,第一次啟動fsc指令時,會啟動一個本地端編譯伺服器(Compile server)來進行一些掃描JAR檔案及初始化動作,然後編譯程式碼:
>fsc Hello.scala

再次啟動fsc指令時,由於編譯伺服器先前已啟動過了,因此只要將程式碼送到伺服器上編譯就可以了,因此可以較快的速度完成編譯的動作。如果想要關閉編譯伺服器,則可以使用-shutdown引數:
>fsc -shutdown
[Compile server exited]

在撰寫具程式進入點的object定義時,可以如上的範例定義main()方法,或者你可以使用Application特徵(Trait),例如:
object Hello extends Application {
println("Hello!Scala!")
}

要使用Application特徵,你使用extends關鍵字,特徵在Scala中可用來定義方法及域(field)成員,以用來混入(mix into)其它類別或物件時擴充其行為,現階段你還不需要深入了解。目前只需要知道,Application特徵宣告了main()方法,你的Hello繼承了這個方法定義(或說是,你的類別繼承了Application的特徵),而你在大括號之間所撰寫的程式碼,其實會是object的主要建構式(Primary constructor),會在物件實例化時執行,結果就是你只要在extends Application之後,在大括號之間撰寫你的程式就可以了,不過這個方法的限制就是,你無法取得命令列引數,而在一些JVM實作中,沒有最佳化物件的初始化程式碼,因此建議只用在相對簡單的應用程式。