けんじの外部記憶です。contentRainbowDevilsLandけんじの外部記憶です。kenji自宅の環境はもう10年以上も24インチデュアルディスプレイ環境でした。動画を見ながらプログラミングをして、同時に資料を見たい場合にデュアルディスプレイだとモニタが足りなくて不便な思いをしていました。そんなとき、「そういえば家に使っていない24インチモニタもう一台あるよな」と思い、さらにDELL製のモニタアームが安かったなと思い出し、ついトリプルモニタにしてしまいました。モニタアームはDELLのMSA14で、1万円ちょっとです。今使っているエルゴトロンのは2万5千ほどした気がするので、だいぶ安いですね。作りはしっかりしていて問題無いです。DELLのモニタであれば、ワンタッチで取り付けることができるのでめちゃ楽です。できあがった環境は次のような感じで、24インチトリプルモニタ。GPU有り版は、Thunderbolt2が2ポートと、HDMIポートが1ポートあるので特に工夫をしなくてもWUXGA(1920×1200)のトリプルモニタが出力可能です。次環境を変えるなら27インチ4kのトリプルディスプレイにしたいところ。SDKに独自に追加したAPIを、一般アプリから参照したくなるときがある。自分のアプリのクラスパスに含めてあげると良い。そのままだと巨大なclasses.jarをapkに含めてしまい、ビルドにとてつもない時間がかかってしまう。そんなときはビルド時のクラスパスに含め、apkの中には含めないようにすればOK。build.gradleのdependenciesにprovidedでファイルを指定してあげれば可能となる。以下の設定はlibs以下のjarをビルド時にはクラスパスに含めますが、apkには含めなくなります。kenjiJavaではすべてのクラスのスーパークラスはObjectですが、ScalaではAnyクラスがすべてのクラスのスーパークラスです。Anyクラスには次のメソッドが定義されています。nullチェックをしてequalsを呼び出す。String詳細はAPIドキュメントで。http://www.scala-lang.org/api/current/index.html#scala.AnyAnyクラスはサブクラスにAnyRefクラスがあり、AnyRefクラスはJavaのObjectクラスの別名になっています。ちなみにJavaの==であるeqはAnyRefクラスで定義されています。AnyRefを継承していないプリミティブ(プリミティブはAnyRefではなくAnyValを継承しています)ではeqはありません。^プリミティブScalaでは、整数をオブジェクトとして処理する必要がある場合に、自動でjava.lang.Integerに変換します。toStringや、Any型の変数に代入しようとしたときなどです。型階層の一番下に、scala.Nullとscala.Nothingクラスがあります。scala.Nullクラスはすべての参照クラス(AnyRef)のサブクラスとして振る舞います。参照クラスのサブクラスとして振る舞うので、値型(AnyVal)とは互換性はありません。Nullクラスの値として、null値が存在します。Nothing型はすべてのクラスのサブクラスとして振る舞います。Nothing型には値はありません。Nothing型の用途の一つはエラーを表すことです。zero")divideはIntを返す関数ですが、errorはNothingを返すと定義することでdivide関数内はもちろん他の型を返す関数内でつかうことができます。kenjiScalaにも抽象クラスがあります。Javaと同じようにabstract修飾子をつけます。Array[String]}contentsメソッドは宣言していますが、定義はありません。定義が無い場合、Javaと違いメソッドの明示的にabstractをつけなくても抽象メンバーとなります。パラメータ無しメソッド次のElementのheightとwidthは括弧がありません。methods)と呼びます。methods)と呼びます。contents(0).length}パラメータが無くミュータブルな状態へのアクセスがオブジェクトのフィールドの読み出しのみの場合はパラメータ無しメソッドを使い、そうで無い場合は空括弧メソッドを使うという習慣があります。defをvalに帰ればメソッドでは無くフィールドとして実装できます。contents(0).length}API利用者からは同じように使えますが、もちろんメソッドとフィールドどちらの実装方法でも動作に違いが無いようにしなければなりません。Javaとの互換性Javaではメソッドの実行とフィールドの参照は記法が区別されています。list.size()やarray.lengthなどです。ScalaはJavaのクラスで同じようにアクセスできるよう、パラメータ無しメソッドと空括弧メソッドはどちらの記法でも呼び出せるようになっています。hogeScalaの関数呼び出しでは、すべての空括弧は省略できます。プロパティの参照以上の意味を持つ場合は空括弧をつける方が良いとなっています。抽象クラスであるElementクラスを継承し、ArrayElementクラスを作ります。Javaと同じようにextends節を記述します。conts}extends節を省略すると、そのクラスは暗黙的にscala.AnyRefを継承します。Javaで言うところのObjectを継承するというのと同じです。メソッドとフィールドのオーバーライドScalaではフィールドとメソッドを統一的に扱っているため、スーパークラスのフィールドをサブクラスのパラメータ無しメソッドでオーバーライドしたり、その逆もできます。そのため、Javaと違い同じ名前でフィールドとパラメータ無しメソッドを定義できません。メソッドがパラメータを取る場合はOKです。1パラメータフィールドの定義Scalaでは、コンストラクタのパラメータをフィールドにすることができます。先ほどのArrayElementは次のように書けます。パラメータにvalをつけるだけです。kenji高階関数のお話です。高階関数はSICPでやったのでさらっと流します。file}“ファイル名が指定した文字列で終わっている”ファイルの一覧の他に、”文字列を含んでいる”や、”正規表現がマッチする”も追加したいとします。そのたびにfor文を含めたメソッドをコピーするのはよろしくありません。するかというと、条件に一致するかどうか判断する関数をパラメータとすることで統一することができます。file}共通化ができたので、それを使うそれぞれの関数は次のようになります。.matches()).endsWith()は一見謎なコードですが、次のコードをプレースホルダーを使って簡潔に書いたものです。fileName.endsWith(query)二つのパラメータfileNameとqueryは、それぞれ1回しか使わないので、プレースホルダーにする事ができます。すると次のコードに短縮できるわけです。.endsWith()クロージャーを使うことでさらに短く書けます。.endsWith())のqueryと、二つ目のアンダースコアは同じものを指しており、二つ目のアンダースコアはqueryと書けます。するとqueryをパラメータとして指定する必要がなくなるので、次のようになります。filesMathing(_.endsWith(query))プレースホルダー構文による関数リテラルと、クロージャーによる自由変数の束縛でここまで短くできるわけですね。この例では、API実装側が重複コードを削減すると言う観点から高階関数を使いました。次はクライアント側の観点で高階関数を使うメリットを紹介します。Int型を含むリストの中に、負数が含まれているかをチェックするcontainsNegと言う関数を考えます。exists}このコードを、値が存在するかチェックする関数をパラメータとして取るexistsメソッドを使うことで簡潔にします。0)Scala標準ライブラリには、このような高階関数でループ処理を簡潔に書くことができるメソッドが多数あります。カリー化カリー化とは、二つ以上のパラメータを取る関数を、一つのパラメータを取る関数に変換する事です。3イメージ的には、curriedSumは、パラメータを一つ取り、”パラメータを一つ取る関数”を返して、それに二つ目の引数を作用させていると言う感じです。次のようにすれば、部分適用された途中の関数を取り出すことができます。3カリー化は一見意味が無いように見えますが、関数型言語では重要な要素です。関数型のプログラミング技術についてはScala関数型デザイン&プログラミングを読むとよりよいかと思います。method)を持つ言語では、引数として関数を取るメソッドを使うことで新しい制御構造を作ることができます。次は、ファイルと”どう書くか”の関数をパラメータとして受け取り、ファイルをオープンして書き込んでクローズする関数です。pattern)と呼ばれているパターンです。java.util.Date)}Scalaは、「引数を一個だけ渡すメソッド呼び出しは、引数を囲む括弧を中括弧に変えて良い」と言う仕様があります。そこで、先ほどのカリー化と組み合わせると、上記のコードは次のように書くことができます。java.util.Date)}まるで言語に組み込まれた制御構造のようです!名前渡しパラメータ名前渡しパラメータは、遅延評価される形で式を関数に渡すことができます。次のアサーションを行うメソッドを考えます。AssertionError//これは次のように使えます。3)名前渡しパラメータを使うと、関数に作用させるときに評価するのでは無く、式を実際に使うまで評価を遅延させることができます。Booleanと()を記述しないことで指定できます。kenjiメソッドオブジェクトのメンバーとして関数を定義するとメソッドになります。外部に公開しない関数として、privateな非公開メソッドがありますが、Scalaでは関数内だけで使用する関数内で定義する関数として、ローカル関数があります。先ほどのコードは次のようになります。}ローカル関数からは外側の関数のパラメータにアクセス可能なので、processLineのパラメータはlineだけになっています。一人前の存在としての関数Scalaの関数はfirst-classな関数です。literals)はあるクラスにコンパイルされ、実行時にインスタンス化すると値としての関数(functionvalues)になります。関数リテラルはソースコード上だけの存在で、関数値(値としての関数)はオブジェクトとして存在します。次はInt型を取り1加算する関数リテラルの例です。1値としての関数はオブジェクトなので、変数に格納することができます。変数に格納しても関数なので通常の関数のように呼び出せます。11関数に複数行コードを入れたい場合、中括弧で囲みます。その関数が返す値はブロック内の最終行の式が生成する値です。101Scalaの多くのライブラリは、この関数リテラルと値としての関数をうまく使えるよう設計されています。すべてのコレクションにはforeashメソッドが定義されており、foreachメソッドは関数をとってそれぞれの要素についてその関数を呼び出します。x))value=-11value=10value=0value=100コレクションについては17章で詳細に説明があります。関数リテラルのパラメータの型は省略可能です。Int)ですが、(x)と書けます。型推論が可能な場合はパラメータの括弧も省略できます。100)プレースホルダー構文もっと関数リテラルを簡潔に書くことができます。パラメータが関数リテラル内で一度しか使われない場合は、アンダースコアでパラメータを使うことができます。100)ただし、プレースホルダー構文を使うには型推論が可能である必要があります。型推論できない場合はエラーになります。_^そんな場合でも型を指定してあげるとOKです。上記のアンダースコアは個別のパラメータの代わりとなるものです。アンダースコアは他にも、パラメータ全体の代わりとして使うこともできます。パラメータ全体をアンダースコアに置き換えている。最初のパラメータをアンダースコアに置き換えている-11100100次の例では3つのパラメータの合計を返すsum関数を考えます。_とすると、0個のパラメータを部分適用した関数を返します。その自動生成された関数にパラメータを入れると元の関数を実行することができます。3)を実行していることになります。6次のようにしてパラメータの一部を埋めた状態で残りのパラメータを入力させる関数を作ることもできます。この場合1つのパラメータを取るapply関数を定義した関数オブジェクトを生成しています。6もしforeachのように、関数呼び出しが必要とされている部分ではアンダースコアさえも省略できます。someNumbers.foreach(println)-11100100関数呼び出しが必要とされている場所以外でこの記法を使うとエラーになります。今までは関数は関数のパラメータだけを参照していましたが、関数の外の変数を参照することも可能です。関数の外にも見つからなければエラーです。more変数が存在すれば参照可能です。variables)です。terms)と呼びます。開いた項は、関数リテラルから関数値を作成するときに自由変数の束縛をつかみ、閉じます。そのためその関数値をクロージャー(closure)と呼びます。クロージャーは自由変数の束縛をつかみます。値では無く変数をつかむので、クロージャー作成後の変数の変更は参照可能です。クロージャーの中で変数に対して変更を加えると、クロージャーの外にも影響します。99連続パラメータJavaで言う所の可変長引数です。関数のパラメータの型の後ろに*を付けることで連続パラメータとなります。“bar”)hogefugafoobar連続パラメータは関数内ではパラメータ型のArrayとなります。Arrayなのであれば連続パラメータとしてArrayを入力としてできそうですが、そのままではコンパイルエラーです。Stringecho(list)パラメータに_*の型を指定すると連続パラメータとして入力可能になります。通常関数の引数は、順番通りにパラメータに設定されます。y=20引数を指定する際にパラメータ名も指定すると、その順番を入れ替えることができます。y=10名前付き引数は次のパラメータのデフォルト値と一緒に使います。パラメータのデフォルト値Scalaではパラメータにデフォルト値を設定することができます。y=20一つ引数を指定すると、最初のパラメータのみ引数の値が設定されます。y=20二つ目の引数だけ値を設定したい場合は名前付き引数を使います。y=100末尾再帰Scalaは末尾再帰の最適化がされます。末尾再帰の最適化をしない場合はscalaシェル実行時かscalacでのコンパイル時に-g:notailcallsをしていします。Scalaの末尾再帰最適化は自分自身の関数を呼び出す際だけにされ、二つの関数を呼び合うような末尾再帰は最適化されません。値としての関数を呼び出す際にも末尾再帰されません。kenjiif式Scalaのif式はJavaのif文と違い、値を返します。if式が値を返すことでより簡潔にコードを記述することができます。"default.txt"上記の例ではvarではなくvalが使えるのもメリットです。等式推論をサポートしやすくなります。“default.txt”)と書くことができます。(これはメリットなのか??コンパイラが一時変数を使わないような最適化を行うことはできるだろうけど、コード的には見づらいだけのような。)whileループScalaにもJavaや他の言語でおなじみのwhileが使えます。b}do-whileもあります。null)whileとdo-whileは式では無くループです。式では無いのでUnitを返します。UnitについてJavaで言う所のvoidですが、voidと違いUnitはUnit値という値があります。Unit値は()で表現します。true()自体は変数名として認識される?whileは純粋関数型言語では無い場合がありますが、Scalaでは互換性のために用意されています。whileは使わずより関数型言語ぽく書く方が良い場合が多いでしょう。上記のgcdLoopは次のように書けます。y)for式Scalaのfor式はJavaのfor文とはだいぶ異なります。for式はコレクションに対する処理を簡潔に書くことができます。filesHereの部分はジェネレータ(generator)と呼び、filesHereから一つずつ取り、valなfileに代入します。filesHereがArray[File]型なのでfileもFile型となります。10とRangeを作れば可能です。sizeとすることで可能です。"+list(i))フィルタリングリストをフィルタリングしたい場合はfor式の中に条件を書くことができます。println(file)複数のフィルタを同時に使うこともできます。println(file)入れ子の反復処理for式に複数の<-節を記述するとループを入れ子にすることができます。line.trim)上記のfor式では括弧ではなく中括弧を使うことでセミコロンが必要という罠を回避できます。line.trim)for式の中での束縛for式の中で変数を定義することも可能です。trimmed)for式の中の変数定義はval変数となります。(Scala的に束縛と変数定義は同義?)for式の結果で新しいコレクションを作成for式の本体の前にyieldキーワードを記述すると、その本体の戻り値をコレクションにする事ができます。filescalaFilesの型はfileがFile型なので、Array[File]になります。for式の本体をブロックにすることももちろん可能です。次の例ではArray[File]でループして、Array[String]を生成しています。}for式はさらに機能があるようなので、第23章でより詳細な解説があるようです。try式による例外処理ScalaにもJavaと同じように例外を投げることができます。IllegalArgumentExceptionまた、throwはNothing型の結果を返します。従って次のように記述することが可能です。println("なんかIOエラー")}Scalaの例外はJavaと違い、throw節で明示的に記述する必要や、try-catchの強制はありません。finally節Scalaにもfinallyがあります。file.close()}また、finally節も値を返します。finally節で値を返すことはせず、ファイルのcloseなど副作用のみにしておくのが良いでしょう。次のコードは2を返します。}しかし次のコードは1を返します。関数型言語のパターンマッチをScalaではmatch式で使うことができます。超高機能なswitchという感じです。println("huh?")}caseにはJavaと違いあらゆる型を指定することができます。高機能なので15章で詳細に解説があります。breakとcontinueはScalaには無いそのような邪悪なものはScalaには必要無いと判断されたようです。(実際には関数リテラルとの絡みで何らかの問題があるようだ)continueはフィルタやif式を、breakはフラグを用いると言うので解決できます。変数のスコープ基本的にJavaと同じです。変数のシャドウイング(shadow)が可能です。println(a)}println(a)Javaでは上記のようなコードは変数の多重定義でエラーですが、Scalaでは動作します。2に続いて1を出力します。kenjiこの章ではイミュータブルなクラスを作成する方法を学びます。作成するクラスは有理数(分数)を表すRationalクラスです。事前条件に違反する場合IllegalArgumentExceptionを投げる。英字かアンダースコアで、その後に英字、数字、アンダースコアが続きます。以上の演算子文字からなる識別子です。+や:、?、~、#などです。一つ以上なので、:::や<?>、:->も有効な演算子識別子です。ミックス識別子ミックス識別子はその名の通り英数字識別子と演算子識別子両方を含む識別子です。unary_+は単項演算子+を定義するメソッドの名前として使用します。他にも、myvar_=は代入演算子を定義するメソッドの名前として使用します。リテラル識別子リテラル識別子はバッククオートで囲まれた任意の文字列を識別子とするものです。`yield`がそうです。Scalaの定数Javaでは定数はすべて大文字のアンダースコア区切りをします。MAX_VALUEなどです。Scalaでは先頭大文字のキャメルケースを使用します。MaxValueなどです。Int型の2は、Rational型を取る*メソッドが無いからです。暗黙の型変換を定義することで実現できます。rを実行することができます。暗黙の型変換は21章でさらに解説があるようです。kenji最近Scalaを使うようにしていますが、なんだかうまく使いこなせていない感があります。それはScalaをしっかり理解していないことから来る不安感なので、飛ばし飛ばし読んだコップ本を再度すみからすみまで読み直してしっかり理解しようと考えています。そこで、毎日コップ本を少しずつ進めていこうと思います。このブログには勉強したことを自分用にメモした内容を書いていきます。基本型Scalaの基本型はJavaと同じです。intやlongなど互換性のためJavaと同じ型が使えますが、Int、LongとScala用の型を使う方が良いです。それぞれscala.Int、scala.Long型が完全名です。String型だけはJavaでもクラスなのでJavaと同じjava.lang.Stringです。scalaパッケージとjava.langパッケージは自動的にimportされるのでそれぞれimportの必要はありません。リテラルJavaと同じです。35lShortとByteは型を指定した上で範囲内の整数値を指定します。範囲外を指定するとエラーになります。32768浮動小数点もJavaと同じです。10.0文字、文字列もJavaと同じです。hogeScalaではより便利な文字列リテラルが使えます。println(“””|hogehoge|fugafuga”””)hogehogefugafuga|を先頭に入れることでインデントを入れてもインデントは無視されるようになります。この章には無いですが、s”i=$i”と文字列リテラルの頭にsを付けることで加工文字列リテラルとする事ができます。(これは便利!)演算子はメソッドScalaの演算子はすべてメソッドです。2としても、内部ではInt型1が持つメソッド+に、パラメータとして2を指定して実行するという意味になります。省略せずに書くと1.+(2)ですね。この記法は中置記法と呼び、パラメータを一つ取るメソッドはすべて中置記法が使えます。“hoge”.indexOf(‘g’)も次のように中置記法が使えます。2前置演算子Scalaでは、-10も10にunary_-と言う名前のメソッドを実行すると言う意味になります。取らないメソッドは空括弧を省略でき、またドットを省略することもできます。ドットを省略した場合後置演算子となります。hogeScalaの慣習では副作用を持つメソッドの実行は空括弧を記述し、副作用を持たないメソッドの実行は空括弧を省略します。オブジェクトの等価性Javaでは==は同じインスタンスかどうかをチェックしますが、Scalaの==はequals呼び出しとなり、等価性をチェックします。Javaの==のような同じインスタンスかどうかをScalaでチェックしたい場合は、eqメソッドを使います。referencesエラーが出ることがあります。メソッドを識別するIDが16bitなので、アプリ全体でメソッド数の上限が65536になっているからです。やって解決するかですが、Multidex(DEXファイルを分割?)か、ProGuardで使っていないメソッドを削除するという方法があります。Studioであれば、Multidexをとても簡単に使えるので、今回はそちらでやってみます。追加するだけでOKです。巨大なjarファイルを追加することによりOOMエラーが出る場合は、同じくbuild.gradleファイルのandroid以下に次の設定を追加するとうまくいくかもしれません。