hamayuzinの日記

エンジニアとかデータサイエンティストとかやってます。あの時 あれやってたな的な備忘録にできれば。

【scala入門】rubyエンジニアがscalaを勉強したメモ その4

trait

  • トレイトを継承することをミックスイン
  • クラスの継承については、ミックスインと呼ばない
  • 特徴
    • クラスパラメーター (コンストラクタ引数) を取ることができない
    • 直接インスタンス化できない
    • 複数のトレイトを 1 つのクラスやトレイトにミックスインできる
    • abstract class キーワードで宣言できる抽象クラスに似ていますが、ひとつのクラスに複数ミックスインできるというところが異なる
  • クラスは複数継承できないが、traitはできる
  • 多重継承による菱型継承問題
    • 解決方法
      • かぶってるmethodを override する
      • super[TraitB].greet() 指定してしまう
    • 線形化(linearization)
      • 継承もとのそれぞれで、かぶっているmethodをoverrideする
      • すると extends ClassA with TraitB with TraitC)だと、一番後ろのものが評価される
  • 自分型アノテーション(self type annotations
    • self: TraitB => みたいなやつ
    • 後からnew するときに、withで対象のtraitをいれる
    • インスタンス生成時に、依存性を選択できるイメージ
  • Scala のクラスおよびトレイトはスーパークラスから順番に初期化される

関数型プログラミング

  • 関数型プログラミング
    • 「副作用のない関数」だけでプログラミングを行うこと
      • 副作用のない関数 = 純粋関数
      • 副作用とは、簡単に言うと、外部の状態を変化させるということ
      • 参照透過性
    • 副作用
      • 変数を変更する
      • オブジェクトが持っているフィールドの値を書き換える
      • 例外やエラーを発生させる
      • コンソールから入力を受け取り、出力を出す
      • ファイルを読み込む、書き込みをする
      • 画面上の GUI を変化させる
  • 無名関数
    • (x: Int, y: Int) => x + y
    • 単なる FunctionN のオブジェクト
    • 引数の最大個数は 22 個
    • 自由に変数に代入したり、引数に渡したり、返り値として返すことができる
      • def メソッドはできない
      • 関数が第一級の値(First Class Object)である
  • カリー化
    • ハスケル・カリーという数学者の名前に由来
    • たとえば (Int, Int) => Int 型の関数のように複数の引数を取る関数があったとき、これを Int => Int => Int 型の関数のように、ひとつの引数を取り、残りの引数を取る関数を返す関数のチェインで表現する
    • 引数を二回に分けていれることができる
      • 1回目の返り値は、2回目の引数をいれてなにかするファンクションとなる
      • 複数ある引数を途中まで確定させた状態の関数を得て使う場合や、値と関数を別々な () で引数として受け取りたい場合に利用
  • 高階関数
    • 関数を引数に取ったり関数を返すメソッドや関数のこと
  • 末尾再帰最適化

型パラメータ

  • 型パラメータ
    • Seq[Int] の [Int] ように [] で与えられる型を受け取る部分が型パラメータ
  • 非変 (invariant)
    • 変位が指定されていない
    • 必ず型が一致
    • サブクラスであろうとだめ
  • 変位指定
    • 共変
      • class G[+T] +をつける
      • サブクラスならOK
    • 反変更
  • 境界
    • 上限境界
      • 型パラメータがどのような型を継承しているかを指定する
      • <:
    • 下限境界
      • 型パラメータがどのような型のスーパータイプであるかを指定
      • >:
    • 多相関数
      • 型パラメータを使って、複数の型に対応できるか
    • 単相関数
      • 1つの型しか対応できないか

エラー処理

  • エラーをraiseさせる
    • throwで投げる
      • throw new IllegalArgumentException("dividerに0は利用できません。")
      • require で発生させる
        • require(divider != 0, "dividerに0は利用できません。")
        • IllegalArgumentException となる
      • try catch
  • option型
    • 値をひとつだけいれることのできるコンテナ
    • some none
    • パターンマッチで取得できる
    • for文でも

either

  • either
    • right left
    • パターンマッチで取得できる
    • rightとleftを同価値としている
    • right 正常値 leftエラー値
    • map とか使う場合は、.rightを使う
  • try
    • Success Failure
  • 使い分け
    • option
      • コレクションの中に存在しなかったり、ストレージ中から条件に合うものを発見できなかったりした場合
    • either
      • Option を使うのでは情報が不足しており、かつ、エラー状態が代数的データ型としてちゃんと定められるものに使う
    • try
      • 非同期プログラミングで使ったり、実行結果を保存しておき、あとで中身を参照したい場合

コレクション

  • list
    • :: コンス
    • 普遍
    • 「副作用のない関数」で処理を表現しやすい
  • array
    • 可変
    • java との兼ね合いで使うことがある
    • toArray toListで行き来
  • set
    • mutable と immutable
    • 重複がゆるされず、自動で削除される
    • ++ は、和集合 全てのものかぶっているもは、片方だけ
    • -- 差集合 かぶっているものを削除
    • intersect 積集合 同じやつだけ
    • 順番を維持しない
  • map
  • その他
    • 末尾追加は圧倒的にarrayの方が早く、先頭追加は圧倒的にlistが早くなっていることがわかると思います。
    • 特にlistなどで 1 万を超える要素数を扱うときは、必ず先頭に追加して、後から並べ直す処理をすることで高速に処理を行うことができます。
    • 実際に 1000 万要素もあるようなコレクションを扱う場合には、listとarrayの場合でarrayの方が 500 から 1000 倍近く早く処理できるということができました

list

  • ++ で結合
  • mkString で 文字列化
  • mapだとできない畳み込みは、foldleftやfoldrightを使う