2012年1月30日月曜日

Scalaでシングルトンパターン

Scalaでシングルトンパターンを書いてみました。
ベターJavaの呼び声高いScalaですが、やはりJavaと全く同じという訳にはいきませんでした。
ちょっと悩んだのでメモとして残します。
objectやstaticの扱いのサンプルにもなると思います。

そもそもScalaでstatic使えるの?
まず、Scalaにはstaticが存在しません。
その代わりに、シングルトンオブジェクトを生成するobjectというものがあります。

なにそれ?
シングルトンオブジェクトという名前が表す通り、シングルトンなオブジェクトです。
特徴として、new演算子を使わなくてもメソッドの実行や変数の参照が出来ます。
ClassName.getInstance() ←こんな感じです。

それってJavaのstaticで宣言されたメソッドとか変数呼び出すのと同じじゃん?
その通りです。呼び出しだけでなく、動作自体もJavaのstaticな変数やメソッドと同じです。
そもそもすでに述べたように、Scalaにはstaticが存在せず、その代わりにobjectという仕組みが用意されているのです。
Javaでstaticとして宣言される変数やメソッドを、Scalaではobjectの中に切り出してあげるのです。

なるほど。じゃあ具体的にどうやって宣言するの?
これはソースを見ていただければ一目瞭然です。
通常、クラスを宣言する際は
class className {...}
となりますが、objectの場合は、
object ObjectName {...}
となります。

ではサンプルソースをご覧ください。

class SingletonSample private( var list:List[Int] ) {

         // リストの先頭に値を追加
        def add( x:Int ) {
            list = x :: list
        }
}

object SingletonSample {

    private val sample:SingletonSample = new SingletonSample((1 to 10).toList)

    def getInstance():SingletonSample = {
         sample
    }

    def apply():SingletonSample = {
         getInstance
    }
}


REPLでの実行結果は以下の通りです。

#インスタンスの生成
scala> val sample = SingletonSample.getInstance
sample: SingletonSample = SingletonSample@151fe8a

#取得したインスタンスの中身(list)をチェック
scala> sample.list
res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

#取得したインスタンス内のリストの先頭に0を追加
scala> sample.add(0)

#0が先頭に追加されていることを確認
scala> sample.list
res3: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

#再度インスタンスを取得してみる
scala> val sample2 = SingletonSample.getInstance
sample2: SingletonSample = SingletonSample@151fe8a

#取得したインスタンスのリストの中身の先頭に0が追加されている
#このことから、シングルトンパターンとして正常に動作していることが分かる
scala> sample2.list
res2: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

ほぉ、簡単ジャン!
ただし気を付けなければならない点が一つあります。
Javaで「staticな変数やメソッド」と、「staticでない変数やメソッド」が入り混じっているクラスの場合、Scalaではstaticな部分をobjectの中に切り出さなければならないのは説明しました。
気を付けなければならない唯一の点とはまさにその切り出し方で、class名とobject名を同一のものにしなければならない「場合がある」という点です。
Scalaでは、class名とobject名が同じものをコンパニオンオブジェクトと呼びます。
この状態が、Javaの「staticな変数やメソッド」と、「staticでない変数やメソッド」が入り混じっているクラスと同じ状態になります。

class名とobject名を同じにしなければならない「場合」って?
サンプルソースを見ていただければ分かると思いますが、シングルトンパターンの場合、実際に生成されるクラスのコンストラクタはprivateにします。
これはJavaでも同じです。シングルトーンパターンなので当然です。
ただ、コンパニオンオブジェクトでない場合、privateでコンストラクタが宣言されているクラスのインスタンスを生成できないのです。
これは、Java的に説明すると、objectが別のクラス内のstaticで宣言されたメソッドや変数という扱いになるためです。
コンパニオンオブジェクトの場合であれば、Java的にはclassとobjectが実質同じクラス内と考えて良いので、インスタンスを生成することができます。

・・・よくわからなくなってきた
極論ではありますが、Javaのstatic混じりのクラスをScalaで書く場合に、staticな変数やメソッドは、クラス名と同じ名前で宣言されたobjectの中に書いてしまえばOKです。
staticなメンバが入っているJavaのクラスHogeがある場合、Scalaではstaticな部分のみ切り出して、Hogeという、クラスと同名のobjectの中に移動してあげるだけです。

ちなみに、コンパニオンオブジェクトを生成したい場合は、同名のclassとobjectを用意するのですが、同一ファイル内に記述しなければならないという制約もあります。

2011年11月9日水曜日

Scalaで文字列中の各出現文字をカウントする

Mapを使ったソースを書いてみようと思ってネタを考えてウダウダした結果、タイトルのようなソースが出来上がりました。
ついでなので関数の部分適用なども使ってみました。

下記サンプルソースに盛り込まれている要素は、
  • Map(mutable)
  • 関数の部分適用
  • 関数のオーバロード
になります。

では早速サンプルソースです。


object CharacterCount {     // scala.collection.mutableをインポートしておけば、mutable.Mapの宣言が短くできる     // インポート無 → cala.collection.mutable.Map[Char, Int]()     // インポート有 → mutableMap[Char, Int]()     import scala.collection.mutable
    /**      * 指定された文字列中に出現する各文字をカウントし、Mapに格納する      * @param text 出現する文字をカウントしたい文字列      * @param limit 出現回数がlimit回以上の文字のみ返す      * @return text中、limit回以上出現した文字と出現回数を格納したMap      */     def getMapWithLimit(text:String, limit:Int):mutable.Map[Char,Int] = {         count(text).filter( (kv) => kv._2 >= limit )     }     /**      * getMapWithLimitの部分適用      * getMapWithLimit(text, 1)と指定したのと同じ      * @param text 出現する文字をカウントしたい文字列      * @return text中、1回以上出現した文字と出現回数を格納したMap      */     def getMap = getMapWithLimit(_:String, 1)     /**      * 部分適用したgetMapをオーバロードしたもの      * getMapWithLimitと全く同じ      * @param text 出現する文字をカウントしたい文字列      * @param limit 出現回数がlimit回以上の文字のみ返す      * @return text中、limit回以上出現した文字と出現回数を格納したMap      */     def getMap(text:String, limit:Int):mutable.Map[Char,Int] = {         getMapWithLimit(text, limit)     }     /**      * 指定された文字列に出現する各文字をカウントし、Mapに格納して返す      * @param text 出現する文字をカウントしたい文字列      * @return text中の各文字と出現回数を格納したMap      */     private def count(text:String):mutable.Map[Char, Int] = {         val map = mutable.Map[Char, Int]()         text.foreach ( (char) => {             // MapのgetOrElseは、第1引数に指定したキーが存在しない場合に、第2引数の値を返します             val count = map.getOrElse( char, 0 )             map.update( char, count+1 )         })         map     }     // 関数の部分適用部分は、以下のようにしても結果は同じ     //def getMap(text:String) = { getMapWithLimit(text, 1) } }

getMap関数(メソッド?)を使うと、文字列中の各文字をキーとし、値に出現回数が格納されたmutable.Mapのインスタンスが返されます。
REPLから試すと以下のとおりです。


scala> val text = "となりのきゃくはよくかきくうきゃくだ。"
text: java.lang.String = となりのきゃくはよくかきくうきゃくだ。

// CharacterCountって打つのが面倒くさいのでccという変数に格納
scala> val cc = CharacterCount
cc: CharacterCount.type = CharacterCount$@2e5facbd

// 出現回数か1回以上の文字を取得(つまり全文字)
scala> cc.getMap(text)
res0: scala.collection.mutable.Map[Char,Int] = Map(の -> 1, か -> 1, う -> 1, く -> 4, ゃ -> 2, と -> 1, き -> 3, な -> 1, は -> 1, よ -> 1, 。 -> 1, り -> 1, だ -> 1)

// 出現回数が3回以上の文字のみ取得
scala> cc.getMap(text, 3)
res1: scala.collection.mutable.Map[Char,Int] = Map(く -> 4, き -> 3)


map.getOrElseに関して、これがScalaの目玉機能の一つであるOption型(Some型とNone型がある)に直結する機能です。JavaであればExceptionが発生しそうなところ、Noneが返されるので結果的に処理が無視される or 指定した処理が実行されることになります。 このOptionに関してはまだ勉強中なのでまた今度サンプルソースを書いてみたいと思っています。

これぐらいのプログラムであれば態々戻り値の型を書かなくても把握できるしScalaが理解できているならコメントもいらないくらいだと思います。(私は理解できていないのでコメントを書きました)
コメントと型の記述を省いて型推論に頼るとこんなにスッキリしました。


object CharacterCount2 {

    def getMapWithLimit(text:String, limit:Int) = {
        count(text).filter( (kv) => kv._2 >= limit )
    }

    def getMap = getMapWithLimit(_:String, 1)

    def getMap(text:String, limit:Int) = {
        getMapWithLimit(text, limit)
    }

    private def count(text:String) = {
        val map = scala.collection.mutable.Map[Char, Int]()
        text.foreach ( (char) => {
            map.update( char, map.getOrElse(char,0)+1 )
        })
        map
    }
}


今回は各文字でカウントアップしましたが、ちょっと工夫すれば単語単位でカウントすることも可能だと思います。
英語やドイツ語であればスペースで文章を区切ってしまえば自動的に単語単位になるので、うまいこと考えれば今年生まれた新語一覧なんかも作れるのかな~と思ったりしてます。

2011年11月3日木曜日

ドイツの歴史(超概要)


ドイツの歴史をざっくりまとめてみました。
本当にざっくりなので後々修正予定です。
しかし学生のころと違って興味を持って歴史を調べると楽しいですね~
なお、この超概要はこのサイト様を参考にさせていただいております。
参考というより、元々とても綺麗に整理されていたものをさらに私が理解できるレベルに箇条書きにした感じです。


1.ガリア遠征(BC58~BC51)などでゲルマン人は傭兵や農民としてローマ帝国に溶け込む


2.ゲルマン民族の大移動を経て、乱立した各地の王国をフランク王国が統一


3.843年のヴェルダン条約によって、分割されたうちの1つである東フランク王国(843年~962年)が現在のドイツの原型となった


4.東フランク王国の国王オットー1世は962年にアウグストゥス(古代ローマ帝国皇帝の称号)を得て、神聖ローマ帝国(962年~1806年)と呼ばれる緩やかな連合体を形成した(長い!)


5.中世におけるドイツには国家としての統一や民族意識はほとんどなく、各地に領邦国家が分立した。これが現在に続く連邦主義の基盤となっているといえる


6.宗教改革では、新旧両教に分かれて互いに争い、三十年戦争ではドイツ全土が徹底的に破壊され、1600万人いたドイツの人口が600万人に減少したといわれる


7.1701年に、北部の領邦君主ホーエンツォレルン家がプロイセン王国(1701年~1918年)を形成した


8.1806年まで神聖ローマ皇帝位を世襲していた「大ドイツ主義」派のハプスブルク家、「小ドイツ主義」派のホーエンツォレルン家とドイツ統一の役割を争った。


9.ナポレオンによる侵略を経て、民族意識と統一国家への志向を強め、19世紀前半にはプロイセンに主導的な役割を期待する気運が高まった。神聖ローマ帝国はナポレオンにの攻勢に屈して解体されハプスブルク家のフランツ2世が1806年に退位した。神聖ローマ帝国の滅亡である。


10.1871年、プロイセン国王ヴィルヘルム1世の戴冠によってドイツはドイツ系オーストリアを除く、小ドイツとしてのドイツ国(ドイツ帝国(1871年~1918年))として統一され、ベルリンを首都とした。(ちなみにこの戴冠式はパリのヴェルサイユ宮殿で行われた)


11.1918年、第1次世界大戦の敗北によって共和制(1919年~1933年)に移行。しかし、ヴァイマル共和制は小党乱立により政局は不安定で、第1次世界大戦後の賠償などもあり、ドイツ国内は驚異的なインフレとなる


12.1933年に、インフレなどを経て、アドルフ・ヒトラー率いるナチス党(国家社会主義ドイツ労働者党)が国民からの支持を受け、政権を握る


13.1939年9月に隣国ポーランドを攻略し、第2次世界大戦が勃発


14.第2次世界大戦に敗北し、オーデル・ナイセ線以東やシュレジェン地域を領土として喪失。さらに、アメリカ、イギリス、フランス、ソビエト連邦の四か国に分割統治される。


15.1949年、盆を暫定的な首都とするドイツ連邦共和国(西ドイツ)と、ベルリンの東部地区(東ベルリン)を首都とするドイツ民主共和国(東ドイツ)に分裂した。


16.1989年ソビエト連邦のペレストロイカに端を発した東ドイツの民主化運動(東欧革命)をきっかけにベルリンの壁が崩壊し、翌1990年に東西ドイツの再統一を果たし、首都を再びベルリンとした。


17.ボンからの連邦政府機関移転(実質的な首都機能移転)や東ベルリンを中心とするベルリンの再開発・インフラ整備を進め、2001年5月2日に、ベルリンへの首都機能移転が完了した。


18.現在ではヨーロッパで最大の国家の一つになる。しかし、東西分裂を原因とする東西の経済格差が影を落としている。
それでもなお、ドイツはフランスとともに欧州連合(EU)の中核国として発言力を増し続けている。
これを再びドイツが周辺国の脅威となると懸念している国もある。

2011年10月27日木曜日

Scalaのファイル入出力のサンプル

Scalaでファイルを入出力するサンプルを書いてみました。
ファイルの入力(読み込み)は専用のクラスがあるのですが、ファイルの出力に関してはなんだか適切な物が無いようです。
なので、ファイルの出力に関してはJavaのクラスを使っています。

ファイルを新規作成して文字列を出力(すでに存在する場合は追記)
その後、作成したファイルを読み込んでいます。
/**
 * Scalaでファイルの入出力
 * Javaのクラスを使ってファイルを作成し、Scalaのクラスを使ってファイルを読み込む
 */
object FileIO {
    def main( args:Array[String] ) {

        // JavaのFileOutputStreamクラスとOutputStreamWriterを別名でimport
        // それぞれインスタンス生成時の1回のみの使用なので別名にする意味は特にないです。
        import java.io.{ FileOutputStream=>FileStream, OutputStreamWriter=>StreamWriter };

        val fileName = "test.txt"
        val encode = "UTF-8"
        val append = true
        
        // 書き込み処理
        val fileOutPutStream = new FileStream(fileName, append)
        val writer = new StreamWriter( fileOutPutStream, encode )

        writer.write("あいうえお\r\n")
        writer.write("かきくけこ\r\n")
        writer.write("さしすせそ\r\n")
        writer.close


        // 読み込み処理(コンソールに出力)
        // 1行で書くとこんな感じ
        // scala.io.Source.fromFile(fileName, encode).getLines.foreach{ println _ }
        val source = scala.io.Source.fromFile(fileName, encode)
        val lines = source.getLines
        lines.foreach{ println _ }


    }
}

2011年10月26日水曜日

Scalaのアクセサメソッドの挙動

Scalaのアクセサメソッド(getterとsetter)について調べたことをまとめます。

下記ページをかなり参考にさせていただきました。
[Scala][Java] Scalaの統一アクセス(プロパティ構文)がなかなかイカしてる件

Scalaはvarかvalを使ってプロパティを宣言すると、自動的にアクセサメソッドを生成してくれます。
さらに、プロパティを直接参照するような書き方をすると、自動的にアクセサメソッドが実行されるようになっています。
そのため、

オブジェクト名.name で、自動生成されたゲッターが実行される
オブジェクト名.name = "abc" で自動生成されたゲッターが実行される

となります。

コンパイルした後に、javapを使って中身を覗いてみると宣言していないメソッドが生成されていることが分かります。

サンプルソース
class Hoge1 {
    var name:String = _
}

object Hoge1Runner {
    def main(args:Array[String]) {
        val obj = new Hoge1
        obj.name = "Tarou";

        // 実行結果は、「Hoge1:Tarou」となる
        println("Hoge1:" + obj.name);
    }
}
javap -private Hoge1の実行結果
  public class Hoge1 extends java.lang.Object implements scala.ScalaObject{
      private java.lang.String name;
      public java.lang.String name();
      public void name_$eq(java.lang.String);
      public Hoge1();
  }

自動的に生成されたアクセサメソッド使ってるって言ってもこれじゃJavaのpublicなプロパティと一緒じゃん。
値のチェックとか必要な場合は結局アクセサメソッド自前で作らなきゃいけないんでしょ?オーバライドできるの?
ということでアクセサをオーバライドしてみました。(オーバライドって言い方が正しいかどうかは分かりませんが)
getterでは、先頭に「Mr.」を、setterでは末尾に「.」を付与するようにしました。

Hoge1Runnerのrun()と、Hoge2Runerのrun()を見比べてみてください。呼び出し側の実行方法は全く変わっていません。
つまり、サクっと開発しておいて、後々呼び出されるクラスの方を修正してしまえば、呼び出し側を変更する必要が無いのです。
Javaだとこうはいきません。オブジェクト名.プロパティ名と書いたコードが山ほどあった場合、呼び出されているクラスでアクセサメソッドを追加した際、呼び出しているプログラムを全て修正する必要があります。
IDEを使っていればアクセサメソッドを自動生成してくれたり、一括置換など便利な機能があるので、特に困ることは無いかもしれませんが、ちょっとしたツールを作りたいという時にはこう言った機能が真価を発揮すると思います。

問題点として、以下のjavap実行結果を見て分かる通り、自動生成されたgetterであるname_()が定義されています。
ということは、実用上問題はないでしょうが、Hoge2#name_ = "aaa" などが実行されると意図したgetterが利用されないということになります。

サンプルソース
class Hoge2 {
    var name_ :String = _

    // getter
    def name  = {
        "Mr." + name_
    }

    // setter
    def name_= (value:String) = {
        name_ = value + "."
    }
}

object Hoge2Runner {
    def main(args:Array[String]) {
        val obj = new Hoge2
        obj.name = "Tarou";

        // 実行結果は「Hoge2:Mr.Tarou.」となる
        println("Hoge2:" + obj.name);

        // 以下の方法だと、用意したgetterが使われないので、実行結果は「Hoge2:Tarou」となります
        //(用意したsetterを使ってないのでピリオドがつかない)
        // val obj2 = new Hoge2
        // obj2.name_ = "Tarou"
        // println("Hoge2:" + obj2.name);
    }
}
javap -private Hoge2の実行結果
public class Hoge2 extends java.lang.Object implements scala.ScalaObject{
    private java.lang.String name_;
    public java.lang.String name_();
    public void name__$eq(java.lang.String);
    public java.lang.String name();
    public void name_$eq(java.lang.String);
    public Hoge2();
}

Hoge2の、意図しないgetterが利用できる問題を解決するためには、プロパティ自体をprivateにする必要があります。
プロパティをprivateにすると、自動生成されるgetterとsetterもprivateになります。
そのため、自動生成されたアクセサには、外部からアクセスでできなくなるため、意図しないアクセサ(自動生成されたアクセサ)が利用できてしまう問題を解消できます。
ただ、いきなりこの形で記述してしまうとScalaでプロパティが自動生成されるメリットが無くなってしまいます。
まずはpublicでプロパティを作っておいて、問題が出たりするタイミングで修正した方が良いかも。
setter自体を用意しなければ外部からの更新を制御することもできます。

サンプルソース
class Hoge3 {
    private var name_ :String = _

    // getter
    def name  = {
        "Mr." + name_
    }

    // setter
    def name_= (value:String) = {
        name_ = value + "."
    }
}

object Hoge3Runner {
    def main(args:Array[String]) {
        val obj = new Hoge3
        obj.name = "Tarou";

        // 実行結果は「Hoge3:Mr.Tarou.」となる
        println("Hoge3:" + obj.name);
        // 以下の方法だと、name_はprivateなのでコンパイルエラー
        // (error: variable name_ in class Hoge3 cannot be accessed in Hoge3)

        // val obj2 = new Hoge3
        // obj2.name_ = "Tarou"
        // println("Hoge3:" + obj2.name);
    }
}

javap -private Hoge3の実行結果
public class Hoge3 extends java.lang.Object implements scala.ScalaObject{
    private java.lang.String name_;
    private java.lang.String name_();
    private void name__$eq(java.lang.String);
    public java.lang.String name();
    public void name_$eq(java.lang.String);
    public Hoge3();
}

Scalaではプロパティのアクセサは自動生成されるなら、そのアクセサはどうやって修正すればいいんだ?と思って調べた結果をまとめました。
間違っている点などあればご指摘頂頂けるとありがたいです。
ちなみに、プロパティをvalで宣言すると、Javaのfinalになり、setterは自動生成されず、getterのみ自動生成されます。
Javaのfinalなので、同じクラス内からも当然値を変更できなくなります。
なんでプロパティ名にアンダーバーが必要なの?というのはまだ理解できていません。
アクセサ自体の書き方も、普通の関数とは違うようなのでまだまだ勉強しなければという感じです。

2011年10月6日木曜日

Eclipse3.7にGoogle Plugin for Eclipseをインストールしようとするとエラーが発生する

Eclipse3.7(Indigo)にGoogle Plugin for Eclipseをインストールしようとすると下記のエラーが発生しました。

1 つ以上の必須項目が見つからないため、インストールを完了できません。 Software being installed: Google App Engine Tools for Android 2.4.1.r37v201109211906 (com.google.gdt.eclipse.mobile.android.feature.feature.group 2.4.1.r37v201109211906) Missing requirement: Android Cloud Tooling 2.4.1.r37v201109211906 (com.google.gdt.eclipse.mobile.android 2.4.1.r37v201109211906) requires 'bundle com.android.ide.eclipse.adt 12.0.0' but it could not be found Cannot satisfy dependency: From: Google App Engine Tools for Android 2.4.1.r37v201109211906 (com.google.gdt.eclipse.mobile.android.feature.feature.group 2.4.1.r37v201109211906) To: com.google.gdt.eclipse.mobile.android [2.4.1.r37v201109211906]

なんかAndroid用のプラグインの依存関係が解決できないよ、というようなエラー。

これは、最初の「使用可能なソフトウェア」のところで、Google App Engine Tools for Android (requires ADT)のチェックを外して上げると解決します。
Android使わないし!という人はこれでも問題ないかと。

2011年10月5日水曜日

ScalaでHashtable系を使ってみる

object Hoge {
    def main(args:Array[String]) {
        import java.util.Hashtable

        // ----------------------------
        // 一番シンプルなパターン
        // ----------------------------
        // Javaだと Hashtable <String,String> hTable = new Hashtable <String,String>();
        val hTable = new Hashtable[String,String]()
        hTable.put("key1", 1.toString)
        hTable.put("key2", 2.toString)

        println(hTable.get("key1"))
        println(hTable.get("key2"))

        println("--------")

        // ----------------------------
        // リストに突っ込んでみる
        // ----------------------------
        //var hTableList:List[Hashtable[String, String]] = List()
        var hTableList = List[Hashtable[String, String]]()
        for ( i <- 1 to 10 ) {
            val hTable = new Hashtable[String,String]()
            hTable.put( "key", i.toString )
            hTableList = hTableList ::: List(hTable)
        }
        hTableList.map( record => println( record.get("key") ) )

        println("--------")

        // ----------------------------
        // せっかくなのでScalaのMapを使ってみる
        // ----------------------------
        //var tableList:List[Map[String,String]] = List()
        var tableList = List[Map[String,String]]()
        for ( i <- 1 to 10) {
            tableList = tableList ::: List( Map("key" -> i.toString) )
        }
        tableList.map( record => println( record.get("key") ) )

        println("--------")

        // ----------------------------
        // リストをもう少しかっこよくする
        // ----------------------------
        val listBuffer = new scala.collection.mutable.ListBuffer[Map[String,String]]
        for ( i <- 1 to 10 ) {
            listBuffer += Map( "key" -> i.toString )
        }
        listBuffer.toList.map( record => println(record.get("key")) )
    }
}