チュートリアル(日本語版)や入門記事など色々なソースで読んだことをメモするページにする予定。おいおい、チートシート的なものにしていければなと。
===============
コンパイル、実行、インタプリタ
> scalac <ソースファイル(.scala)> // コンパイル
> fsc <ソースファイル(.scala)> // コンパイル
> scala <クラス名> // 実行
> scala <スクリプトファイル(.scala)> // インタプリタ実行
> scala // 対話インタプリタ起動
- fsc はコンパイラデーモン。起動しておけば、2回目以降のコンパイルが速くなる(らしい)。fsc -shutdown で停止。
変数、メソッド、型
val <変数名>:<型> = <値>
var <変数名> = <初期値>:<型>
def <メソッド名>(<仮引数>:<型>, ...):<戻り値の型> = {
// メソッドの中身
}
// 戻り値がUnitの場合の省略形
def <メソッド名>(<仮引数>:<型>, ...) {
// メソッドの中身
}
- val キーワード:再代入不可な変数を宣言 (Javaでいうと final つき変数)
- var キーワード:再代入可能な変数を宣言
- def キーワード:メソッドを宣言
- (コンパイラが推論できる限り、)型指定は省略できる。メソッド仮引数の型の省略は不可。
- 処理本体が1文の場合は { } を省略可
- メソッド戻り型がUnit(Javaのvoidに相当)の場合、戻り型と = を省略できる
(例)
val x:Int = 5
val x = 5 // 型省略
var str:String = "abc"
var str = "abc" // 型省略
def sum(x:Int, y:Int):Int = {
x + y
}
def sum(x:Int, y:Int) = x + y // 戻り型省略、{ } 省略
// Unitメソッド
def greetMsg() {
println("hello!")
}
メインメソッド
object <シングルトンクラス名> {
def main(args: Array[String]) {
// 処理...
}
}
object <シングルトンクラス名> extends Application {
// 処理...
}
- objectキーワード:シングルトンオブジェクト(インスタンスを1つだけもつクラス)の宣言。(正確ではないと思うけれど)Javaのstaticに相当。
- mainメソッドはJavaと同じく文字列の配列をとる。
- Application trait を継承すると、mainメソッドのシグネチャが省略できる。この場合引数をとることはできない。
(例)
object HelloWorld {
def main(args: Array[String]) {
println("hello world!")
}
}
object HelloWorld {
println("hello world!")
}
パッケージインポート
import <パッケージ名>.<クラス名>
import <パッケージ名>.{<クラス名>,<クラス名>,...} // 複数クラスをまとめてインポート
import <パッケージ名>._ // 指定パッケージのクラスをすべてインポート
(例)
import java.util.{Date, Locale}
import java.text.DateFormat
import java.text.DateFormat._
制御構文 : if, while, for, (構文じゃないけど)foreach
if (条件式) { ... } else if { ... } else { ... }
while (条件式) { ... }
for (<変数> <- <コレクションオブジェクト>) { ... }
<コレクションオブジェクト>.foreach(<変数(要素が順に入る)> => <関数オブジェクト>
- 処理本体が1文の場合は { } を省略可。
(例)
if (x < y) { println("x < y") } else if (x > y){ println("x > y") } else { println("x == y") }
while (i > 0) {
println("countdown: " + i)
i -= 1
}
for (str <- array) println(str)
array.foreach(elem => println(elem))
関数をとる関数(高階関数)
def <メソッド名>(<仮引数>,...,<仮引数(メソッド名)>: <メソッド引数の型> => <メソッド戻り値の型>,...):<戻り値の型> {
// 処理
}
(例)
def inc(n:Int):Int = n + 1
def printResult(n:Int, func:Int=>Int):Unit = println("result = " + func(n))
scala> printResult(3,inc)
result = 4
無名関数
(例)
import java.util._
import java.text.DateFormat
import java.text.DateFormat._
def log(msg:String, makeLogMessage:String=>String):Unit =
println(makeLogMessage(msg))
log("error message...", (msg:String) =>
"[" + getDateTimeInstance().format(new Date) + "] " + msg
)
クラスとインスタンス
class <クラス名>(<コンストラクタ仮引数>,...) {
val <変数名> = <値> // パブリック変数
def <メソッド名>(<仮引数>,...) = { ... } // パブリックメソッド
private val <変数名> = <値> // プライベート変数
private def <メソッド名>(<仮引数>,...) = { ... } // プライベートメソッド
}
// インスタンス化
val <変数名> = new <クラス名>(<コンストラクタ引数>,...)
// メンバー変数・メソッドへのアクセス
<インスタンス>.<メンバー変数名>
<インスタンス>.<メンバーメソッド>(<引数>,...)
- クラス名のあとに、基本コンストラクタの引数を続けて書く
- コンストラクタ引数に val をつけると引数と同名のインスタンス変数とゲッターメソッドが、var をつけるとさらにセッターメソッドが自動的に追加される
- 変数やメソッド宣言のあたまに private をつけるとプライベートメンバー(なにもつけなければパブリックメンバー)
(例)
class Dog(val name:String) {
def bark() = println("わん。")
}
val pochi = new Dog("ポチ")
println("pochi.name=" + pochi.name)
pochi.bark
アブストラクトクラス、継承、オーバーライド
abstract class <クラス名> // アブストラクトクラス宣言
class <サブクラス名> extends <スーパークラス名> // 継承
override def <メソッド名> // メソッドオーバーライド
- スーパークラスの実装メソッドをオーバーライドする場合は、override キーワードをつけないとエラー。(抽象メソッドをオーバーライドする場合はつけなくても大丈夫だった)
(例)
abstract class Dog(val name:String) {
def bark = println("わん。")
}
class Chihuahua(n:String) extends Dog(n:String) {
override def bark = println("きゃん。")
}
(メモ) スーパークラスの指定にコンストラクタを明記しないとエラーになった
Trait
- Javaのインタフェースに実装をもたせられるようにしたもの(※不正確なたとえ)
- インスタンスは作れない
- Classを継承したTraitを宣言することが可能
- Traitを継承したClassを宣言することが可能
- Mix-in的に使う場合はwithキーワードを使う
// Traitの宣言
trait MyTrait
// Classを継承したTraitを宣言
class Animal
trait HasLegs extends Animal
// Traitを継承したClassを宣言
trait Rectangular
class Rectangle extends Rectangular
// Mix-in
class Animal
trait HasLegs extends Animal
trait FourLegged extends HasLegs
class Cat extends Animal with FourLegged
(例) Programming in Scala Chap. 12.5 のExampleより
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
override def toString = buf.toString
}
trait Incrementing extends IntQueue {
// abstract メソッドの中で親クラスのabstractメソッドを呼ぶことができる
// Traitのみで許される書き方(Classでは許されない)
abstract override def put(x: Int) { super.put(x + 1) }
}
trait Filtering extends IntQueue {
abstract override def put(x: Int) {
if (x >= 0) super.put(x)
}
}
scala> val queue = (new BasicIntQueue with Incrementing with Filtering)
queue: BasicIntQueue with Incrementing with Filtering = ArrayBuffer()
scala> queue.put(-1)
scala> queue.put(0)
scala> queue.put(1)
scala> queue
res20: BasicIntQueue with Incrementing with Filtering = ArrayBuffer(1, 2)
scala> val queue = (new BasicIntQueue with Filtering with Incrementing)
queue: BasicIntQueue with Filtering with Incrementing = ArrayBuffer()
scala> queue.put(-1)
scala> queue.put(0)
scala> queue.put(1)
scala> queue
res24: BasicIntQueue with Filtering with Incrementing = ArrayBuffer(0, 1, 2)
- Traitが参照するsuperは実行時に決まる
- 複数のTraitをMix-inする場合は、順序に注意(右端から適用されていく)
JavaクラスをScalaで使う
- JavaのクラスをScalaコード内で new して使える。特別なライブラリ等は必要なし。
- クラス継承やインタフェース実装も可。
(例)Javaクラスを継承したScalaクラス
// MediaPlayer.java
public abstract class MediaPlayer {
public abstract void play();
}
// mediaplayer.scala
class CDPlayer extends MediaPlayer {
def play = println("playing CD...")
}
class DVDPlayer extends MediaPlayer {
def play = println("playing DVD...")
}
val p1:MediaPlayer = new CDPlayer()
val p2:MediaPlayer = new DVDPlayer()
p1.play
p2.play
// コンパイル・実行
$ javac MediaPlayer.java
$ scala mediaplayer.scala
playing CD...
playing DVD...
ScalaクラスをJavaで使う
- ScalaのクラスをJavaコード内で new して使える。コンパイル・実行にはscalaのライブラリが必要。
- クラス継承も可(Traitはどういう扱いになるんだろう)。
(例)Scalaクラス継承したJavaクラス
// Person.scala
abstract class Person(val name:String) {
def greetingMsg():String
def greet():Unit = println(greetingMsg)
}
** メソッド戻り型を省略すると、Javaで継承するときエラーになった。ちゃんと調べてないが、Javaから使うクラスを書く場合(そんなことしないと思うけど...)は、型まわりをきっちり書いておく必要がありそう。
// PersonMain.java
public class PersonMain {
public static void main(String[] args) {
Person p1 = new Japanese("やまだたろう");
Person p2 = new American("John Smith");
p1.greet();
p2.greet();
}
}
class Japanese extends Person {
public Japanese(String name) {
super(name);
}
public String greetingMsg() {
return "こんにちは";
}
}
class American extends Person {
public American(String name) {
super(name);
}
public String greetingMsg() {
return "Hi.";
}
}
// コンパイル・実行
$ scalac Person.scala
$ javac -cp .:$SCALA_HOME/lib/scala-library.jar PersonMain.java
$ java -cp .:$SCALA_HOME/lib/scala-library.jar PersonMain
こんにちは
Hi.
... or ...
$ scala PersonMain
こんにちは
Hi.
===============
変更履歴
- 2009.11.28 Traitの記述を追加
===============
つづく。。。
0 件のコメント:
コメントを投稿