scaladocを読むために

scaladoc読んで勉強してても記号が多いのとよく分からないキーワードが出てきて読みづらい。
気になったものを調べてまとめる。

よく出てくるのは以下だ。

  • AnyはJavaでいうObject型。
  • UnitはJavaでいうvoid。

可変長引数

以下はMap#+メソッド。*の部分。

def +(kvs: (A, B)*): Map[A, B]

implicitパラメータ

例えばList#maxByメソッド。

def maxBy[B](f: (A) ⇒ B)(implicit cmp: Ordering[B]): A

implicitが付いているメソッド引数は省略可能。省略すればデフォルトのものが適用されるが、自分で指定することも可能。
まず省略バージョン。

    val list = List("one", "two", "three", "four")
    val result = list.maxBy(_.length) // 一番文字列長の長いthreeが返る

次に並び替えの仕組みを独自Orderingで変える。無名traitを生成して対応。

    val result2 = list.maxBy(_.length){ // 一番文字列長の長いthreeが返る
      new Ordering[Int]{
        def compare(x: Int, y: Int) = x - y
      }
    }

    val result3 = list.maxBy(_.length){ // 一番文字列長の短いoneが返る
      new Ordering[Int]{
        def compare(x: Int, y: Int) = y - x
      }
    }

implicit付変数宣言をしておくと、第二引数省略してもそれが使用される。

implicit val ordering = new Ordering[Int]{
    def compare(x: Int, y: Int) = y - x
}
val result = list.maxBy(_.length) // one

カリー化されたメソッド

以下はList#foldのscaladoc。

def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1

このように使う。

val list = List(1,2,3,4)
val result = list.fold(10)((e1,e2) => e1 + e2) // 実際の処理は10+1+2+3+4が行われる

ただ、2番目の引数は(ではなく{で記述されることが多い。

val result = list.fold(10){(e1,e2) => e1 + e2}

ジェネリクス

Ancestor > Parent > Childというようなクラス階層になっているとして。

上限境界

以下の例だと、Parent及びサブクラスChild。

class Sample[T <: Parent](x: T) {}
下限境界

以下の例だと、Parent及びスーパークラスAncestor。

class Sample[T >: Parent(x: T) {}

先のfoldメソッドのscaladocをもう一度引用すると

def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1

となっている。このメソッドで使用するのはA1というAの下限境界型。よって、、、

class Ancestor(var x:Int) {}
class Parent(var y:Int) extends Ancestor(y){}
class Child(var z:Int) extends Parent(z) {}

val list:List[Parent] = List(new Parent(1), new Parent(2))
val result = list.fold(new Ancestor(10)){(e1, e2) => e2.x = e1.x + e2.x; e2;}

List[Parent]に対して、変数zには親のAncestorが渡せる。この場合、A1はAncestorになるので、e1.xというアクセスになる。
一方、変数zのところを、new Parent(10)としたならば、e1.xではコンパイルエラーとなり、正しくはe1.yとなる。

共変

Mapの場合、こんなふうになっている。

trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, Map[A, B]]

このvalueの型が+となっており、共変を表す。つまり以下はOKとなる。

var map1:Map[String, Parent] = Map("k1" -> new Parent())
var map2:Map[String, Child] = Map("k2" -> new Child())

map1 = map2

ただし、keyの型は共変ではないのでこれはダメ。コンパイルエラーとなる。

var map3:Map[Parent, String] = Map(new Parent() -> "v3")
var map4:Map[Child, String] = Map(new Child() -> "v4")

map3 = map4
反変

もし上記Mapのvalueの型に-がついて反変だったら、Map[String, Ancestor]のインスタンスがmap1に代入できる。

Lift

Liftアプリケーション用テンプレートのDL

%git clone https://github.com/lift/lift_25_sbt.git

必要ライブラリのDL

%cd lift_25_sbt/scala_29/lift_basic
%./sbt

待つこと数分・・・
sbtプロンプトが出るので、InteliJで読み込みができるようにする。

>gen-idea

待つこと数分・・・
終了したらInteliJでOpenからlift_basicを選べば開くことが出来る。

アプリケーションを実行するには引き続きsbtプロンプト上で以下を実行。

>container:start

ブラウザで、http://localhost:8080でアクセス可能。

テーブルごとの行数を出す

SQLServerの話。
userというテーブル名をもつテーブルを曖昧検索してそれぞれの行数を出すSQL

select o.name, i.rows
from sysindexes i, sysobjects o
where
o.xtype = 'U'
and o.id = i.id
and i.indid < 2
and o.name LIKE '%user%'

Intellij IDEAのsbt consoleで文字化け解消

specs2でのユニットテストの練習。
で、Intellij IDEAのsbt consoleで実行したら日本語が化ける・・・。コンソール上のsbtでも同様に日本語が化ける。。
色々調べて以下の情報に。意外と見つからなかった。

参考:http://qiita.com/items/3fd54c5b697104904176

まず文字コードのチェック。

scala> scala.io.Codec.default.charSet
res0: java.nio.charset.Charset = Shift_JIS

おぉやっぱり。俺はUTF-8で作ってるんでね。
VM引数にUTF-8であることを設定(-Dfile.encoding=UTF-8)。
f:id:mtoyoshi:20130513000134p:plain
再度実行。

scala> scala.io.Codec.default.charSet
res0: java.nio.charset.Charset = UTF-8

よし。テスト実行!
日本語ちゃんと表示されました。

sbt gen-idea

sbt gen-idea

を実行すると、

[error] Not a valid command: gen-idea
[error] Expected '/'
[error] Expected ':'
[error] Not a valid key: gen-idea
[error] gen-idea
[error]         ^

と表示された。コマンドとして認識していない模様。

標準コマンドでは無いようなのでプラグインとして追加。

plugins.sbt

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.3.0")

projectフォルダに上記内容を記述したplugins.sbtを設置。
これで上記エラーはなくなりました。
あとは、Intelijでプロジェクトをオープンするだけ。

※Play frameworkだとエラーになるという情報が多くありました。