Android Studioで、ビルド時だけ参照しapkに含めないjarファイルを設定する

Androidのフレームワークの開発をしていると、Android SDKに独自に追加したAPIを、一般アプリから参照したくなるときがある。
そんなときはビルド後のout/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jarをコピーして、
自分のアプリのクラスパスに含めてあげると良い。

しかし、そのままだと巨大なclasses.jarをapkに含めてしまい、ビルドにとてつもない時間がかかってしまう。
そんなときはビルド時のクラスパスに含め、apkの中には含めないようにすればOK。
build.gradleのdependenciesにprovidedでファイルを指定してあげれば可能となる。
以下の設定はlibs以下のjarをビルド時にはクラスパスに含めますが、apkには含めなくなります。

dependencies {
    provided fileTree(dir: "libs", include: '*.jar')
    compile 'com.android.support:appcompat-v7:22.1.1'
}

コップ本をやる 第11章 Scalaの階層構造

JavaではすべてのクラスのスーパークラスはObjectですが、ScalaではAnyクラスがすべてのクラスのスーパークラスです。
Anyクラスには次のメソッドが定義されています。

// nullチェックをしてequalsを呼び出す。
final def ==(that: Any): Boolean
final def !=(that: Any): Boolean

// Javaのequalsと一緒
def equals(that: Any): Boolean

// JavaのhashCodeと一緒
def hashCode: Int

// 数値型とnull以外はhashCodeと同じ
def ##: Int

// JavaでもおなじみのtoString
def toString: String

詳細はAPIドキュメントで。
http://www.scala-lang.org/api/current/index.html#scala.Any

AnyクラスはサブクラスにAnyRefクラスがあり、AnyRefクラスはJavaのObjectクラスの別名になっています。
ちなみにJavaの==であるeqはAnyRefクラスで定義されています。なのでAnyRefを継承していないプリミティブ(プリミティブはAnyRefではなくAnyValを継承しています)ではeqはありません。

scala> 1 eq 1
<console>:11: error: value eq is not a member of Int
       1 eq 1
         ^

プリミティブ

Scalaでは、整数をオブジェクトとして処理する必要がある場合に、自動でjava.lang.Integerに変換します。
たとえば1 toStringや、Any型の変数に代入しようとしたときなどです。

// Any型に入れるとjava.lang.Integer

scala> var a:Any = 1
a: Any = 1

scala> a.getClass
res11: Class[_] = class java.lang.Integer

// そのままだとInt
scala> 1.getClass
res12: Class[Int] = int

最下位(bottom)の二つの型

型階層の一番下に、scala.Nullとscala.Nothingクラスがあります。

scala.Nullクラスはすべての参照クラス(AnyRef)のサブクラスとして振る舞います。
参照クラスのサブクラスとして振る舞うので、値型(AnyVal)とは互換性はありません。
Nullクラスの値として、null値が存在します。

Nothing型はすべてのクラスのサブクラスとして振る舞います。
Nothing型には値はありません。
Nothing型の用途の一つはエラーを表すことです。

たとえば次のような例です。

def error(message: String): Nothing =
  throw new RuntimeException(message)

def divide(x: Int, y: Int): Int =
  if (y != 0) x / y
  else error("can't divide by zero")

divideはIntを返す関数ですが、errorはNothingを返すと定義することでdivide関数内はもちろん他の型を返す関数内でつかうことができます。

コップ本をやる 第10章 合成と継承

Scalaにも抽象クラスがあります。Javaと同じようにabstract修飾子をつけます。

abstract class Elemen {
  def contents: Array[String]
}

contentsメソッドは宣言していますが、定義はありません。
定義が無い場合、Javaと違いメソッドの明示的にabstractをつけなくても抽象メンバーとなります。

パラメータ無しメソッド

次のElementのheightとwidthは括弧がありません。括弧をつけないメソッドはパラメータ無しメソッド(oarameterless methods)と呼びます。
空の括弧をつけてパラメータ無しメソッドも定義することもでき、こちらは空括弧メソッド(empty-paren methods)と呼びます。

abstract class Element {
  def contents: Array[String]
  def height: Int = contents.length
  def width: Int = if (height == 0) 0 else contents(0).length
}

パラメータが無くミュータブルな状態へのアクセスがオブジェクトのフィールドの読み出しのみの場合はパラメータ無しメソッドを使い、そうで無い場合は空括弧メソッドを使うという習慣があります。
また、defをvalに帰ればメソッドでは無くフィールドとして実装できます。

abstract class Element {
  def contents: Array[String]
  val height: Int = contents.length
  val width: Int = if (height == 0) 0 else contents(0).length
}

API利用者からは同じように使えますが、もちろんメソッドとフィールドどちらの実装方法でも動作に違いが無いようにしなければなりません。

Javaとの互換性
Javaではメソッドの実行とフィールドの参照は記法が区別されています。list.size()やarray.lengthなどです。
ScalaはJavaのクラスで同じようにアクセスできるよう、パラメータ無しメソッドと空括弧メソッドはどちらの記法でも呼び出せるようになっています。

scala> "hoge".toString
res2: String = hoge

scala> "hoge".toString()
res3: String = hoge

Scalaの関数呼び出しでは、すべての空括弧は省略できます。しかし、プロパティの参照以上の意味を持つ場合は空括弧をつける方が良いとなっています。

"Hello".length // 副作用が無いので括弧無し
println()      // 副作用があるので括弧あり

クラスの拡張

抽象クラスであるElementクラスを継承し、ArrayElementクラスを作ります。
Javaと同じようにextends節を記述します。

class ArrayElement(conts: Array[String]) extends Element {
  def contents: Array[String] = conts
}

extends節を省略すると、そのクラスは暗黙的にscala.AnyRefを継承します。
Javaで言うところのObjectを継承するというのと同じです。

メソッドとフィールドのオーバーライド

Scalaではフィールドとメソッドを統一的に扱っているため、スーパークラスのフィールドをサブクラスのパラメータ無しメソッドでオーバーライドしたり、その逆もできます。
そのため、Javaと違い同じ名前でフィールドとパラメータ無しメソッドを定義できません。メソッドがパラメータを取る場合はOKです。

// 同じ名前でもパラメータを取ればOK

scala> class WontCompile {
     | var f = 0
     | def f(i: Int) = 1
     | }
defined class WontCompile

scala> var a = new WontCompile()
a: WontCompile = WontCompile@1ae8bcbc

scala> a.f
res8: Int = 0

scala> a.f(1)
res9: Int = 1

パラメータフィールドの定義

Scalaでは、コンストラクタのパラメータをフィールドにすることができます。
先ほどのArrayElementは次のように書けます。パラメータにvalをつけるだけです。

class ArrayElement(
  val contents: Array[String]
) extends Element

コップ本をやる 第9章 制御の抽象化

高階関数のお話です。
高階関数はSICPでやったのでさらっと流します。

object FileMatcher{
  private def filesHere = (new java.io.File(".")).listFiles

// ファイル名がqueryで指定した文字列で終わっているファイルの一覧を取得する関数
  def filesEnding(query: String) =
    for (file <- filesHere; if file.getName.endsWith(query))
      yield file
}

“ファイル名が指定した文字列で終わっている”ファイルの一覧の他に、”文字列を含んでいる”や、”正規表現がマッチする”も追加したいとします。
そのたびにfor文を含めたメソッドをコピーするのはよろしくありません。
ではどうするかというと、条件に一致するかどうか判断する関数をパラメータとすることで統一することができます。

def filesMatching(query: String, matcher: (String, String) => Boolean) = {
  for (file <- filesHere; if matcher(file.getName, query))
    yield file
}

共通化ができたので、それを使うそれぞれの関数は次のようになります。
def filesEnding(query: String) =
filesMathing(query, .endsWith())

def filesContaining(query: String) =
filesMathing(query, .contains())

def filesRegex(query: String) =
filesMathing(query, .matches())

.endsWith()は一見謎なコードですが、次のコードをプレースホルダーを使って簡潔に書いたものです。
(fileName: String, query: String) => fileName.endsWith(query)

二つのパラメータfileNameとqueryは、それぞれ1回しか使わないので、プレースホルダーにする事ができます。
すると次のコードに短縮できるわけです。
.endsWith()

クロージャーを使うことでさらに短く書けます。
filesMathing(query, .endsWith())のqueryと、二つ目のアンダースコアは同じものを指しており、二つ目のアンダースコアはqueryと書けます。
するとqueryをパラメータとして指定する必要がなくなるので、次のようになります。

private def filesMatching(matcher: String => Boolean) =
  for (file <- filesHere; if matcher(file.getName))
    yield file
def filesEnding(query: String) =
  filesMathing(_.endsWith(query))

プレースホルダー構文による関数リテラルと、クロージャーによる自由変数の束縛でここまで短くできるわけですね。
この例では、API実装側が重複コードを削減すると言う観点から高階関数を使いました。
次はクライアント側の観点で高階関数を使うメリットを紹介します。

まず、Int型を含むリストの中に、負数が含まれているかをチェックするcontainsNegと言う関数を考えます。

def containsNeg(nums: List[Int]): Boolean = {
  var exists = false
  for (num <- nums)
    if (num < 0)
      exists = true
  exists
}

このコードを、値が存在するかチェックする関数をパラメータとして取るexistsメソッドを使うことで簡潔にします。
def containsNeg(nums: List[Int]): Boolean = nums.exists(_ < 0)

Scala標準ライブラリには、このような高階関数でループ処理を簡潔に書くことができるメソッドが多数あります。

カリー化

カリー化とは、二つ以上のパラメータを取る関数を、一つのパラメータを取る関数に変換する事です。

// カリー化していない普通の関数
scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int, y: Int)Int

scala> plainOldSum(1, 2)
res0: Int = 3

//カリー化された関数
scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Int

scala> curriedSum(1)(2)
res1: Int = 3

イメージ的には、curriedSumは、パラメータを一つ取り、”パラメータを一つ取る関数”を返して、それに二つ目の引数を作用させていると言う感じです。
次のようにすれば、部分適用された途中の関数を取り出すことができます。
scala> val onePlus = curriedSum(1)_
onePlus: Int => Int =

scala> onePlus(2)
res2: Int = 3

カリー化は一見意味が無いように見えますが、関数型言語では重要な要素です。
関数型のプログラミング技術についてはScala関数型デザイン&プログラミングを読むとよりよいかと思います。

新しい制御構造を作る

一人前の値としての関数(first class method)を持つ言語では、引数として関数を取るメソッドを使うことで新しい制御構造を作ることができます。

次は、ファイルと”どう書くか”の関数をパラメータとして受け取り、ファイルをオープンして書き込んでクローズする関数です。
関数にリソースを貸し出すので、ローンパターン(loan pattern)と呼ばれているパターンです。

def withPrintWriter(file: File, op: PrintWriter => Unit) {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}

// 次のように使います。
withPrintWriter(
  new File("data.txt")
  writer => writer.println(new java.util.Date)
}

Scalaは、「引数を一個だけ渡すメソッド呼び出しは、引数を囲む括弧を中括弧に変えて良い」と言う仕様があります。
そこで、先ほどのカリー化と組み合わせると、上記のコードは次のように書くことができます。

def withPrintWriter(file: File)(op: PrintWriter => Unit) {
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
    writer.close()
  }
}

// 次のように使います。
val file = new File("data.txt")
withPrintWriter(file) {
  writer => writer.println(new java.util.Date)
}

まるで言語に組み込まれた制御構造のようです!

名前渡しパラメータ

名前渡しパラメータは、遅延評価される形で式を関数に渡すことができます。
次のアサーションを行うメソッドを考えます。

// 名前渡しパラメータを使わないバージョン
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
  if (assertionsEnabled && !predicate())
    throw new AssertionError

//これは次のように使えます。
myAssert(() => 5 > 3)

// 名前渡しパラメータを使うバージョン
def myAssert(predicate: => Boolean) =
  if (assertionsEnabled && !predicate)
    throw new AssertionError

// 次のようにあたかも組み込みの制御構造のように使えます
myAssert(5 > 3)

名前渡しパラメータを使うと、関数に作用させるときに評価するのでは無く、式を実際に使うまで評価を遅延させることができます。
名前渡しにするには、() => Booleanではなく、=> Booleanと()を記述しないことで指定できます。

コップ本をやる 第8章 関数とクロージャー

メソッド

オブジェクトのメンバーとして関数を定義するとメソッドになります。

object LongLines {
  def processFile(filename: STring, width: Int) {
    val source = Source.fromFile(filename)
    for (line <- source.getLines())
      processLine(filename, width, line)
  }

private def processLine(filename: String, width: Int, line: String) {
    if (line.length > width)
      println(filename + ": " + line.trim)
  }
}

ローカル関数

外部に公開しない関数として、privateな非公開メソッドがありますが、Scalaでは関数内だけで使用する関数内で定義する関数として、ローカル関数があります。
先ほどのコードは次のようになります。

  def processFile(filename: STring, width: Int) {
    def processLine(line: String) {
      if (line.length > width)
        println(filename + ": " + line.trim)
    }
    val source = Source.fromFile(filename)
    for (line <- source.getLines())
      processLine(filename, width, line)
  }

ローカル関数からは外側の関数のパラメータにアクセス可能なので、processLineのパラメータはlineだけになっています。

一人前の存在としての関数

Scalaの関数はfirst-classな関数です。
関数リテラル(function literals)はあるクラスにコンパイルされ、実行時にインスタンス化すると値としての関数(functionvalues)になります。
関数リテラルはソースコード上だけの存在で、関数値(値としての関数)はオブジェクトとして存在します。

次はInt型を取り1加算する関数リテラルの例です。
(x: Int) => x + 1

値としての関数はオブジェクトなので、変数に格納することができます。変数に格納しても関数なので通常の関数のように呼び出せます。

scala> var increase = (x: Int) => x + 1
increase: Int => Int =

scala> increase(10)
res0: Int = 11

関数に複数行コードを入れたい場合、中括弧で囲みます。その関数が返す値はブロック内の最終行の式が生成する値です。
scala> var increase = (x: Int) => {
x + 100
x + 10
x + 1
}
increase: Int => Int =

scala> increase(100)
res2: Int = 101

Scalaの多くのライブラリは、この関数リテラルと値としての関数をうまく使えるよう設計されています。
たとえばすべてのコレクションにはforeashメソッドが定義されており、foreachメソッドは関数をとってそれぞれの要素についてその関数を呼び出します。
scala> val someNumbers = List(-11, 10, 0, 100)
someNumbers: List[Int] = List(-11, 10, 0, 100)

scala> someNumbers.foreach((x: Int) => println(“value=” + x))
value=-11
value=10
value=0
value=100

コレクションについては17章で詳細に説明があります。

関数リテラルの短縮形

関数リテラルのパラメータの型は省略可能です。
scala> someNumbers.filter((x) => x > 0)
res4: List[Int] = List(10, 100)

パラメータは(x: Int)ですが、(x)と書けます。

さらに、型推論が可能な場合はパラメータの括弧も省略できます。
scala> someNumbers.filter(x => x > 0)
res5: List[Int] = List(10, 100)

プレースホルダー構文

もっと関数リテラルを簡潔に書くことができます。
パラメータが関数リテラル内で一度しか使われない場合は、アンダースコアでパラメータを使うことができます。
scala> someNumbers.filter(_ > 0)
res6: List[Int] = List(10, 100)

ただし、プレースホルダー構文を使うには型推論が可能である必要があります。
型推論できない場合はエラーになります。

scala> val f = _ + _
:10: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
val f = _ + _
^
:10: error: missing parameter type for expanded function ((x$1: , x$2) => x$1.$plus(x$2))
val f = _ + _
^

そんな場合でも型を指定してあげるとOKです。
scala> val f = (:Int) + (:Int)
f: (Int, Int) => Int =

scala> f(1, 2)
res7: Int = 3

部分適用された関数

上記のアンダースコアは個別のパラメータの代わりとなるものです。
アンダースコアは他にも、パラメータ全体の代わりとして使うこともできます。

scala> someNumbers.foreach(println _) // パラメータ全体をアンダースコアに置き換えている。
-11
10
0
100

scala> someNumbers.foreach(println(_)) // 最初のパラメータをアンダースコアに置き換えている
-11
10
0
100

次の例では3つのパラメータの合計を返すsum関数を考えます。
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (a: Int, b: Int, c: Int)Int

scala> val a = sum _
a: (Int, Int, Int) => Int =

scala> a(1, 2, 3)
res11: Int = 6

sum _とすると、0個のパラメータを部分適用した関数を返します。
そしてその自動生成された関数にパラメータを入れると元の関数を実行することができます。

内部的には3つのパラメータを取るapply関数が定義された関数オブジェクトを生成しており、a(1, 2, 3)はa.apply(1, 2, 3)を実行していることになります。
scala> val a = sum _
a: (Int, Int, Int) => Int =

scala> a.apply(1, 2, 3)
res15: Int = 6

次のようにしてパラメータの一部を埋めた状態で残りのパラメータを入力させる関数を作ることもできます。
この場合1つのパラメータを取るapply関数を定義した関数オブジェクトを生成しています。
scala> val a = sum(1, _: Int, 3)
a: Int => Int =

scala> a(2)
res12: Int = 6

もしforeachのように、関数呼び出しが必要とされている部分ではアンダースコアさえも省略できます。
scala> someNumbers.foreach(println)
-11
10
0
100

関数呼び出しが必要とされている場所以外でこの記法を使うとエラーになります。
scala> val a = sum
:11: error: missing arguments for method sum;
follow this method with `_’ if you want to treat it as a partially applied function

クロージャー

今までは関数は関数のパラメータだけを参照していましたが、関数の外の変数を参照することも可能です。

もちろん関数の外にも見つからなければエラーです。
scala> val a = (x: Int) => x + more
:10: error: not found: value more
val a = (x: Int) => x + more

変数が存在すれば参照可能です。
scala> val more = 10
more: Int = 10

scala> val a = (x: Int) => x + more
a: Int => Int =

関数から見ると、moreは自由変数(free varibles)で、xは束縛変数(bound variables)です。
束縛変数だけ使っている関数リテラルは閉じた項(closed terms)と呼び、自由変数を使っている関数リテラルは開いた項(open terms)と呼びます。

開いた項は、関数リテラルから関数値を作成するときに自由変数の束縛をつかみ、閉じます。そのためその関数値をクロージャー(closure)と呼びます。

クロージャーは自由変数の束縛をつかみます。
つまり値では無く変数をつかむので、クロージャー作成後の変数の変更は参照可能です。
また、クロージャーの中で変数に対して変更を加えると、クロージャーの外にも影響します。

scala> var sum = 0
sum: Int = 0

scala> someNumbers.foreach(sum += _)

scala> sum
res20: Int = 99

連続パラメータ

Javaで言う所の可変長引数です。
関数のパラメータの型の後ろに*を付けることで連続パラメータとなります。

scala> def echo(args: String) =
| for (arg <- args) println(arg)
echo: (args: String
)Unit

scala> echo(“hoge”,”fuga”,”foo”, “bar”)
hoge
fuga
foo
bar

連続パラメータは関数内ではパラメータ型のArrayとなります。

Arrayなのであれば連続パラメータとしてArrayを入力としてできそうですが、そのままではコンパイルエラーです。

scala> def list = List(“1”, “2”, “3”)
list: List[String]

scala> echo(list)
:13: error: type mismatch;
found : List[String]
required: String
echo(list)

パラメータに_*の型を指定すると連続パラメータとして入力可能になります。
scala> echo(list: _*)
1
2
3

名前付き引数

通常関数の引数は、順番通りにパラメータに設定されます。

scala> def func1(x: Int, y: Int) = println(s”x=$x, y=$y”)
func1: (x: Int, y: Int)Unit

scala> func1(10,20)
x=10, y=20

引数を指定する際にパラメータ名も指定すると、その順番を入れ替えることができます。
scala> func1(y = 10, x = 20)
x=20, y=10

名前付き引数は次のパラメータのデフォルト値と一緒に使います。

パラメータのデフォルト値

Scalaではパラメータにデフォルト値を設定することができます。

scala> def func2(x: Int = 10, y: Int = 20) = println(s”x=$x, y=$y”)
func2: (x: Int, y: Int)Unit

scala> func2()
x=10, y=20

一つ引数を指定すると、最初のパラメータのみ引数の値が設定されます。
scala> func2(100)
x=100, y=20

二つ目の引数だけ値を設定したい場合は名前付き引数を使います。
scala> func2(y = 100)
x=10, y=100

末尾再帰

Scalaは末尾再帰の最適化がされます。
末尾再帰の最適化をしない場合はscalaシェル実行時かscalacでのコンパイル時に-g:notailcallsをしていします。

ただ、Scalaの末尾再帰最適化は自分自身の関数を呼び出す際だけにされ、二つの関数を呼び合うような末尾再帰は最適化されません。
また、値としての関数を呼び出す際にも末尾再帰されません。

コップ本をやる 第7章 組み込みの制御構造

if式

Scalaのif式はJavaのif文と違い、値を返します。if式が値を返すことでより簡潔にコードを記述することができます。

val filename =
  if (!args.isEmpty) args(0)
  else "default.txt"

上記の例ではvarではなくvalが使えるのもメリットです。
また、等式推論をサポートしやすくなります。
println(filename)と書く代わりに、println(if (!args.isEmpty) args(0) else “default.txt”)と書くことができます。

(これはメリットなのか??コンパイラが一時変数を使わないような最適化を行うことはできるだろうけど、コード的には見づらいだけのような。)

whileループ

ScalaにもJavaや他の言語でおなじみのwhileが使えます。

def gcdLoop(x: Long, y: Long): Long = {
  var a = x
  var b = y
  while (a != 0) {
    val temp = a
    a = b % a
    b = temp
  }
  b
}

do-whileもあります。

do {
  line = readLine()
  println("Read: " + line)
} while (line != null)

whileとdo-whileは式では無くループです。式では無いのでUnitを返します。

Unitについて

Javaで言う所のvoidですが、voidと違いUnitはUnit値という値があります。
Unit値は()で表現します。

scala> def greet() { println(“Hello”) }
greet: ()Unit

scala> greet() == ()
Hello
res0: Boolean = true

()自体は変数名として認識される?

whileは純粋関数型言語では無い場合がありますが、Scalaでは互換性のために用意されています。
ただ、whileは使わずより関数型言語ぽく書く方が良い場合が多いでしょう。上記のgcdLoopは次のように書けます。

def gcd(x: Long, y: Long): Long =
  if (y == 0) x
  else gcd(y, x % y)

for式

Scalaのfor式はJavaのfor文とはだいぶ異なります。(より高機能になっています!) for式はコレクションに対する処理を簡潔に書くことができます。

val filesHere = (new java.io.File(".")).listFiles
for (file <- filesHere)
  println(file)

file <- filesHereの部分はジェネレータ(generator)と呼び、filesHereから一つずつ取り、valなfileに代入します。filesHereがArray[File]型なのでfileもFile型となります。

よくある1から10までのループも1 to 10とRangeを作れば可能です。

for (i <- 1 to 10)
  println("i=" + i)

添字のための0からsize-1までのループは 0 to size -1ではなく、0 until sizeとすることで可能です。

for (i <- 0 until size)
  println("list(" + i + ")= "+list(i))

フィルタリング
リストをフィルタリングしたい場合はfor式の中に条件を書くことができます。

for (file <- filesHere if file.getName.endsWith(".scala"))
  println(file)

複数のフィルタを同時に使うこともできます。

for (
  file <- filesHere
  if file.isFile
  if file.getName.endsWith(".scala"))
  println(file)

入れ子の反復処理
for式に複数の<-節を記述するとループを入れ子にすることができます。

for (
  file <- filesHere
  if file.getName.endsWith(".scala")); // <- ここにセミコロンが必要!
  line <- fileLines(file)
  if line.trim.matches(pattern)
) println(file + ": " + line.trim)

上記のfor式では括弧ではなく中括弧を使うことでセミコロンが必要という罠を回避できます。

for {
  file <- filesHere
  if file.getName.endsWith(".scala")) // <- 中括弧はセミコロンが必要無い
  line <- fileLines(file)
  if line.trim.matches(pattern)
} println(file + ": " + line.trim)

for式の中での束縛
for式の中で変数を定義することも可能です。

for {
  file <- filesHere
  if file.getName.endsWith(".scala")) // <- 中括弧はセミコロンが必要無い
  line <- fileLines(file)
  trimmed = line.trim
  if trimmed.matches(pattern)
} println(file + ": " + trimmed)

for式の中の変数定義はval変数となります。
(Scala的に束縛と変数定義は同義?)

for式の結果で新しいコレクションを作成

for式の本体の前にyieldキーワードを記述すると、その本体の戻り値をコレクションにする事ができます。

def scalaFiles =
  for {
    file <- filesHere
    if file.getName.endsWith(".scala"))
  } yield file

scalaFilesの型はfileがFile型なので、Array[File]になります。
for式の本体をブロックにすることももちろん可能です。
また次の例ではArray[File]でループして、Array[String]を生成しています。

def scalaFileNames =
  for {
    file <- filesHere
    if file.getName.endsWith(".scala"))
  } yield {
    val filename = file.getName
    filename
  }

for式はさらに機能があるようなので、第23章でより詳細な解説があるようです。

try式による例外処理

ScalaにもJavaと同じように例外を投げることができます。

throw new IllegalArgumentException

また、throwはNothing型の結果を返します。
従って次のように記述することが可能です。

val half =
  if (n % 2 == 0)
    n / 2
  else
    throw new RuntimeException("n must be event")

例外のキャッチ

try {
  val f = new FileReader("input.txt")
} catch {
  case ex: FileNotFoundException => println("ファイルが無いよ!")
  case ex: IOException => println("なんかIOエラー")
}

Scalaの例外はJavaと違い、throw節で明示的に記述する必要や、try-catchの強制はありません。

finally節
Scalaにもfinallyがあります。

val file = new File("input.txt")
try {
  // ファイルを使う
} finally {
  file.close()
}

また、finally節も値を返します。しかしfinally節で値を返すことはせず、ファイルのcloseなど副作用のみにしておくのが良いでしょう。
次のコードは2を返します。
def f(): Int = try { return 1 } finally { return 2 }

しかし次のコードは1を返します。(どういう理由で動作が違う?)
def g(): Int = try { 1 } finally { 2 }

match式

関数型言語のパターンマッチをScalaではmatch式で使うことができます。超高機能なswitchという感じです。

val firstArg = if (args.length > 0) args(0) else ""
firstArg match {
  case "salt"  => println("pepper")
  case "chips" => println("salsa")
  case "eggs"  => println("bacon")
  case _       => println("huh?")
}

caseにはJavaと違いあらゆる型を指定することができます。
高機能なので15章で詳細に解説があります。

breakとcontinueはScalaには無い

そのような邪悪なものはScalaには必要無いと判断されたようです。
(実際には関数リテラルとの絡みで何らかの問題があるようだ)

continueはフィルタやif式を、breakはフラグを用いると言うので解決できます。

変数のスコープ

基本的にJavaと同じです。
ただ、変数のシャドウイング(shadow)が可能です。

val a = 1
{
  val a = 2
  println(a)
}
println(a)

Javaでは上記のようなコードは変数の多重定義でエラーですが、Scalaでは動作します。
2に続いて1を出力します。

コップ本をやる 第6章 関数型スタイルのオブジェクト

この章ではイミュータブルなクラスを作成する方法を学びます。
作成するクラスは有理数(分数)を表すRationalクラスです。

// nとdはクラスパラメータで、その二つを取る基本コンストラクタ
class Rational(n: Int, d: Int) {

  // 事前条件を指定する
  // 事前条件に違反する場合IllegalArgumentExceptionを投げる。
  require(d != 0)

  // フィールド、メソッド定義以外を基本コンストラクタとしてコンパイルする
  private val g = gcd(n.abs, d.abs)

  // フィールド定義
  val numer: Int = n / g
  val denom: Int = d / g

  // 補助コンストラクタ
  // Scalaの補助コンストラクタでは、最初の処理で同じクラスの他のコンストラクタを呼ぶ必要がある
  def this(n: Int) = this(n, 1)

  // オーバーライドする際はメソッド定義にoverride修飾子を付ける
  override def toString = n + "/" + d

  // 有理数の加算
  def + (that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom)

  // 有理数の乗算
  def * (that: Rational): Rational =
    new Rational(
      numer * that.numer, denom * that.denom)

  // メソッドの多重定義
  def * (i: Int): Rational =
    new Rational(numer * i, denom)

  // thisで自己参照する
  def lessThan(that: Rational) =
    this.numer * that.denom < that.numer * this.denom

  // 非公開のメソッド
  private def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)
}

object Main {
  def main(args: Array[String]): Unit = {
    val r1 = new Rational(10, 15)
    val r2 = new Rational(9, 15)
    println("print "+r1)
    println("r1 + r2 = "+ (r1 + r2))
    // *は+よりも優先度が高い
    println("r1 + r2 * r2 = "+ (r1 + r2 * r2))
    println("r1 < r2 ? "+ (r1 lessThan r2))
    println("r2 < r1 ? "+ (r2 lessThan r1))

  }
}

Scalaの識別子

Scalaの識別子には、英数字識別子、演算子識別子、ミックス識別子、リテラル識別子の4つがあります。

英数字識別子

先頭が英字かアンダースコアで、その後に英字、数字、アンダースコアが続きます。$も英字に含まれますが$はScalaコンパイラのために予約されているので使わないでおきましょう。

演算子識別子

一つ以上の演算子文字からなる識別子です。たとえば+や:、?、~、#などです。一つ以上なので、:::や<?>、:->も有効な演算子識別子です。

ミックス識別子

ミックス識別子はその名の通り英数字識別子と演算子識別子両方を含む識別子です。たとえばunary_+は単項演算子+を定義するメソッドの名前として使用します。他にも、myvar_=は代入演算子を定義するメソッドの名前として使用します。

リテラル識別子

リテラル識別子はバッククオートで囲まれた任意の文字列を識別子とするものです。`x`, `<client>`, `yield`がそうです。

Scalaの定数

Javaでは定数はすべて大文字のアンダースコア区切りをします。たとえばMAX_VALUEなどです。Scalaでは先頭大文字のキャメルケースを使用します。たとえばMaxValueなどです。

暗黙の型変換

メソッドの多重定義により、r * 2のような演算は定義できましたが、2 * rは実行できません。Int型の2は、Rational型を取る*メソッドが無いからです。しかし、暗黙の型変換を定義することで実現できます。
scala> implicit def intToRational(x: Int) = new Rational(x)
を実行することで2 * rを実行することができます。
暗黙の型変換は21章でさらに解説があるようです。

コップ本をやる 第5章 基本型と演算子

最近Scalaを使うようにしていますが、なんだかうまく使いこなせていない感があります。それはScalaをしっかり理解していないことから来る不安感なので、飛ばし飛ばし読んだコップ本を再度すみからすみまで読み直してしっかり理解しようと考えています。そこで、毎日コップ本を少しずつ進めていこうと思います。このブログには勉強したことを自分用にメモした内容を書いていきます。

第5章 基本型と演算子

基本型

Scalaの基本型はJavaと同じです。intやlongなど互換性のためJavaと同じ型が使えますが、Int、LongとScala用の型を使う方が良いです。それぞれscala.Int、scala.Long型が完全名です。String型だけはJavaでもクラスなのでJavaと同じjava.lang.Stringです。

scalaパッケージとjava.langパッケージは自動的にimportされるのでそれぞれimportの必要はありません。

リテラル

Javaと同じです。

// 16進数
val hex = 0x5
val hex2 = 0x00FF

// 8進数
val oct = 035

// Long
val a = 35L
val b = 35l

ShortとByteは型を指定した上で範囲内の整数値を指定します。
範囲外を指定するとエラーになります。

scala> val a: Short = 32767
a: Short = 32767

scala> val a: Short = 32768
:10: error: type mismatch;
found : Int(32768)
required: Short
val a: Short = 32768

浮動小数点もJavaと同じです。

//小数点を付けるとDouble
scala> val a = 10.0
a: Double = 10.0

// dを付けるとDouble
scala> val a = 10d
a: Double = 10.0

// fを付けるとFloat
scala> val a = 10f
a: Float = 10.0

文字、文字列もJavaと同じです。
scala> val a = ‘b’
a: Char = b

scala> val a = “hoge”
a: String = hoge

Scalaではより便利な文字列リテラルが使えます。
println(“””|hogehoge
|fugafuga”””)
hogehoge
fugafuga

|を先頭に入れることでインデントを入れてもインデントは無視されるようになります。

この章には無いですが、s”i=$i”と文字列リテラルの頭にsを付けることで加工文字列リテラルとする事ができます。(これは便利!)

演算子はメソッド

Scalaの演算子はすべてメソッドです。
1 + 2としても、内部ではInt型1が持つメソッド+に、パラメータとして2を指定して実行するという意味になります。省略せずに書くと1.+(2)ですね。この記法は中置記法と呼び、パラメータを一つ取るメソッドはすべて中置記法が使えます。

// “hoge”.indexOf(‘g’)も次のように中置記法が使えます。
scala> “hoge” indexOf ‘g’
res6: Int = 2

前置演算子

Scalaでは、-10も10にunary_-と言う名前のメソッドを実行すると言う意味になります。前置演算子として定義できるのは-,+,!,~の4つだけです。

後置演算子

引数を取らないメソッドは空括弧を省略でき、またドットを省略することもできます。ドットを省略した場合後置演算子となります。

scala> “HOGE” toLowerCase
res8: String = hoge

Scalaの慣習では副作用を持つメソッドの実行は空括弧を記述し、副作用を持たないメソッドの実行は空括弧を省略します。

オブジェクトの等価性

Javaでは==は同じインスタンスかどうかをチェックしますが、Scalaの==はequals呼び出しとなり、等価性をチェックします。
Javaの==のような同じインスタンスかどうかをScalaでチェックしたい場合は、eqメソッドを使います。

scala> “hoge” eq “hoge”
res18: Boolean = true

scala> “hoge” eq new String(“hoge”)
res17: Boolean = false

AndroidでToo many method referencesが出た場合

Androidの開発をしていて、巨大なjarファイルを使ったりすると、ビルド時にToo many method referencesエラーが出ることがあります。
メソッドを識別するIDが16bitなので、アプリ全体でメソッド数の上限が65536になっているからです。

で、どうやって解決するかですが、Multidex(DEXファイルを分割?)か、ProGuardで使っていないメソッドを削除するという方法があります。

Android Studioであれば、Multidexをとても簡単に使えるので、今回はそちらでやってみます。

app/build.gradleファイルの、android.defaultConfig部分に、 multiDexEnabled = true を追加するだけでOKです。

また、巨大なjarファイルを追加することによりOOMエラーが出る場合は、同じくbuild.gradleファイルのandroid以下に次の設定を追加するとうまくいくかもしれません。

Windowsでemacsキーバインド+IME操作

Windowsでemacsキーバインドを使いたい場合、AutoHotKeyを使っていたが、keyhacの方が便利ということでkeyhacに移行した。

そしてIMEをキーひとつで切り替えることができるように設定を変更した。
Kinesisキーボードを使っているのでEndキーでIME OFF、Page DownキーでIME ONだ。
EndとPage Downは別のキーにリマップして使うかもしれないので、EndキーをF11に、Page DownキーをF12にリマップして使う。
キーボード上でリマップできるのは非常に楽で便利だ。

keyhacはこちらから入手する。
emacsキーバインドはこちらから設定をもらう。ただ、この設定は左Ctrlしかemacsキーバインドになってくれないので注意する。

そして次の設定を追記する。これでF11でIME OFF、F12でIME ONとなる。
F11とF12はKinesisキーボードで使いやすいキーにリマップする。
IME切り替え部分のコードはこちらからいただいた。