2009年10月10日土曜日

[Scala] Scala チートシート (未完)

ちょっとずつ Scala を勉強中です。
チュートリアル(日本語版)や入門記事など色々なソースで読んだことをメモするページにする予定。おいおい、チートシート的なものにしていければなと。

===============

コンパイル、実行、インタプリタ

> 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 件のコメント:

コメントを投稿