Open1

Scala

dowanna6dowanna6

Scala

チュートリアル

https://docs.scala-lang.org/overviews/scala-book/two-types-variables.html

  • ビルド
    • JVMで動作する
  • チュートリアルを見てるとobjectにmainメソッドを定義するとscalacで自動的に実行される?
    • objectに対してdefされたメソッドはコンパイル後にpublic static void mainに変換されるためJVMが実行するらしい
  • object extends Appでも同じ効果が得られる
    • Appの中にmainのtraitが定義されているため(traitとmethodは違う。traitはabstract的なものかな)
    • ?objectにメソッドを定義することなく定義したブロックはコンストラクタ的な扱いになるんだろうか
  • ?scalacしたら実行可能ファイル出来上がるかな〜と持ったら$.class,.class,.tastyファイルが出てきた。どれ実行するんだ
    • ?man scalac -> no manual entry for scalac
    • scalac Hello ビルド後のクラス名を指定すれば実行できた

基本的な要素

  • valは不変、varは可変
    • REPLではvalは再定義できるから注意が必要
  • single-quoteはchar、double-quoteはstring
  • s"$x $y" みたいな形式で文字列を結合できる
    • s"${1+1}" とか波括弧でかこうと式を実行できる
  • 複数行の文字列は"""で囲うと宣言できる
    • 改行すると地味にインデックスされてしまうのでパイプから始めて最後に.stripMarginすると整形される
  • def
    • 引数がなければカッコも要らないっぽい
      • def hoge = println("hogehoge")
      • hoge
      • みたいな感じで呼び出せる
  • expression vs statement
    • expression -> 戻り値がある
    • statement -> 戻り値なし、副作用あり
    • scalaではexpressionに寄せたい
  • 条件分岐
    • if
      • if (true) a else b で三項演算子っぽくかけて楽
    • for
      • for (n <- seq) println(n) (val seq = Seq(1,2,3))
        • 右から左に代入されるのが最初だけ少し戸惑いそう
        • ListとSequenceとArrayなどは区別されているがlinear collectionの一つ
          • collectionはforeachできる
            • seq.foreach(println)
          • ?List
          • ?Sequence
          • ?Array
          • Map
            • ハッシュマップ的なやつ
            • for ((key,value) <- map) println(s"keyとmapだよ") みたいな使い方
            • map.foreach { case (key,value) => println(...) } みたいな使い方も可能
              • ?caseは何を見て合致判定してるんだろう、型を指定してるわけでもないのに
          • ?Set
      • for loopは要素に対して副作用を発生させるのに対してfor expressionは戻り値がある
      • 基本for expressionに寄せたい
        • val namelist = List("a","b")
        • for (n <- namelist) yield n.capitalize
      • yield
        • yieldの後にblockを宣言することも可能(最後に値をreturnするのを忘れないように)
          • return書かなくて済むの良いな
        • yield忘れたらどうなるんだろう
          • 空っぽのListになってた
        • return書いたらどうなるんだろう
          • return outside methodって怒られた
    • match
      • caseの中にifくっつけられて便利
      • methodのbodyを全部match文にできる
      • case _ はdefaultの定義
      • catch文の中にも同じ書き方が使える
    • class
      • class Person(var f: String, var l: String)
        • varをvalに変えればread-onlyになる。便利
        • ?getter/setterどう定義するんだろう
        • class直下に(methodの外で)定義されたbodyはコンストラクタとして実行される
        • bodyの中で val hoge = "hoge"とか定義すればread-onlyのpublic property 'hoge'が追加される
      • class内に this() の名前でメソッドを定義すると、一部引数などが省略されたときのコンストラクタを追加できる
        • 引数の省略ぐらいならデフォルト値をPerson(var f: String = "default")って設定すれば良いけど
        • もうちょい複雑なことをしたければ使うこともあるのかな
        • その後チュートリアルにも利用は稀と書いてあった
    • trait
      • extends X with Y with Z で複数extendしたclassを作成できる
      • traitにはabstractも具体的な実装も定義できる
      • override defで具体的な実装を上書きできる
      • インスタンス化の瞬間にtraitを混ぜることもできる
        • val d = new Dog() extends X with Yみたいな
    • abstract
      • constructorをtraitに定義したい時に使う
      • 使うのは稀って書いてあったけどrepositoryパターンとかこれを使わず定義できるのかな
        • ここにいろんな方法が紹介されてた
          • メソッドインジェクションとか、インジェクションが必要な関数を返すとか
    • collection
      • ArrayBuffer
        • 可変なのでOOPから来た人が馴染みやすい
        • +=すれば要素が追加、-=すれば要素が削除される(要素がなければ何も起きない)
        • ++=すれば他のcollectionと結合できる
        • append,clear,とかメソッドも用意されている
      • List
        • 隣接リスト、不変
        • 新しいリストを作成するには +: を使う
          • List(1,2) ++: existingList みたいな
          • 1 +: existingList みたいな(prepend)
          • existingList :+ 1 もできる(append)
        • 片方向リストなのでappendは遅め、prependの方が速い
        • 大きなリストの最後の方にアクセスしたい、appendしたいなどのニーズがあればvectorの方が適している
          • collectionの種類を意識する機会がtsよりは多そう
        • val list = 1 :: 2 :: 3 :: Nilとも定義できる(片方向リストだと最後の要素はNilを示すため)
        • (1 to 10).toListでも定義できる
      • Vector
        • 基本はlistと同じだけどindexされている([0]ではなく(0)でアクセスするのに注意)
        • Listも同じようにindexでアクセスできた。パフォーマンス上の違いってことかな
      • Map
        • forなら(for(k,v) <- map)
        • forEachならmap.forEach { case (k,v) => ... }
      • Set
        • 重複なし
        • 追加しようとしてもただ無視される
        • sortedSetとかlinkedHashSetあるから選ぶときは目を通すべし
    • sequence操作
      • seq.map(_ * 2)
        • scalaで_はいろんなところに登場する
        • 変数を特に定義したくない時は_でも事足りる。便利
        • for(x <- list) yield x * 2でもok
        • list.map(x => x * 2)でもok
        • def double = (i: Int) => i * 2の後にlist.map(double)でもok
      • mapをList[Int]に対して実行するとint -> int型の関数を期待されるので、合致すればなんでもok
        • type inferenceあるからval stringList: List[String] = list.mapすると、ちゃんとint->String型の式を求めてくれる
        • filterはint -> boolean型
      • seq.reduce(_ + _)
        • これでlist内の全要素の合計
        • 最初ちょっと慣れない
      • Map(連想配列の方)
        • ?m.view.filterKeys().toMap のようにviewを経由するらしいが、この意味はまだわかっていない
        • mutable mapの場合は += で要素を追加したり、++= で他のmapと結合できる
          • ? +: と+= は何が違うんだろう(listとmap)
            • 同じcollectionだから +: の方じゃないのかな〜と思った
            • +:(collection全般) は ::(List) を裏側で呼び出すらしい
    • tuple
      • val(x,y,z) = (1,'a',"hoge")みたいな感じで分割代入できる
    • method
      • def hoge(i: Int) = ??? と書くと未実装でもコンパイルは通る
        • 呼び出すとエラー

sbt

  • := はscalaではなくsbt独自のsyntax