Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ゼロから始めるScala文法 (再)

329 views

Published on

A talk at Scala Kansai Summit 2018, originally presented by Amaya-san in 2017.

Published in: Software
  • Be the first to comment

  • Be the first to like this

ゼロから始めるScala文法 (再)

  1. 1. (bitly url)
  2. 2. おことわり Scala関西 Summit 2017でamayaさ んによって行なわれた講演の再演で す Scalaをはじめよう! ─マルチパラ ダイム言語への招待─ https://nextpublishing.jp/book/9497.ht ml 2018-11-10ゼロから始めるScalaプロジェクト 2
  3. 3. 参考サイトたち ひしだま's 技術メモ Scala http://www.ne.jp/asahi/hishidama/home/tech/scala/index.html 網羅的 Scala Text (ドワンゴ社による研修資料) https://dwango.github.io/scala_text/ 言語学的な部分〜実務まで Scala公式ドキュメント http://docs.scala-lang.org / 最近整備された Scala Standard Library API http://www.scala-lang.org/api/current/index.html Google先生が苦手な記号でも検索できる 2018-11-10ゼロから始めるScalaプロジェクト 3
  4. 4. What's Scala? 「Scalable Language」 「オブジェクト指向」・「関数型」両方の特性を持つ強い静的型 付け言語 強い静的型付け言語だが, コンパイラの補助が強力・コードが簡潔 実態は「関数型由来の便利ツールを利用できるオブジェクト指向型言 語」 ちょっとしたスクリプト〜大規模分散環境まで広く適用可能 JVMで動作 Javaのライブラリ資産も利用可能, Javaコードと併用可能 最近は ネイティブ (LLVM)/JavaScript でも結構動く sbtがビルドツールのデファクトスタンダード これだけ入れておけばok オーバーヘッドな し scala コマンドは不 要 2018-11-10ゼロから始めるScalaプロジェクト 4
  5. 5. Scalaの良いところ 構文や標準ライブラリが洗練されており, 処理を簡潔に書ける ⇔ Java 配列とリストを同じように扱いたいのに配列だけ構文が違う… 統一的に扱えます 変数宣言のシグネチャが冗長… コンパイラの型推論におまかせ デフォルト引数・名前付き引数が… あります Thread/ExecutorService面倒… 非同期処理に便利なやつが標準ライブラリにあります ⇔ Light-weight Language ランタイムエラーが怖い… 型はある種のテスト 2018-11-10ゼロから始めるScalaプロジェクト 5
  6. 6. Scalaの悪いところ コンパイルが遅い? よく勘違いされるポイント 初めてコンパイルして遅すぎて投げた → 初回はScala本体や依存解決のダウンロードがあるため特別遅い コンパイルの度にsbtを起動している → JVM起動の時間があるため. sbtは立ち上げっぱなしにしておく それでも比較的遅い…アップデートで改善されつつある 表現力が高いが故に, 同じ処理に様々な実現方法があ る 「一つの処理に唯一の記述方法を」としているPythonの対極 特に, 個々では便利な糖衣構文が複数合わさると 全く異なる見た目になってしまう 2018-11-10ゼロから始めるScalaプロジェクト 6
  7. 7. Scalaで意識すべきこと (関数型もできるが) 基本はオブジェクト指向 出来る限り不変な値を使う 以上 2018-11-10ゼロから始めるScalaプロジェクト 7
  8. 8. Hello World! object Main { def main(args: Array[String]): Unit = { val message1 = "Hello" var message2 = "World" message2 += "!" println(message1 + " " + message2) } } エントリポイン ト メソッド 再代入可変数 改行付標準出力 再代入不可変数 型は推論される 2018-11-10ゼロから始めるScalaプロジェクト 8
  9. 9. Hello World! def main(args: Array[String]): Unit = { val message1 = "Hello" var message2 = "World" message2 += "!" println(message1 + " " + message2) } 仮引数 仮引数の型 「文字列」の「配 列」 [] は多相の記号 返り値の型 Unit は返り値が 無いことを意味する 型 (≒void) 式: 計算が行われ, 必ず値を返す returnは不要 2018-11-10ゼロから始めるScalaプロジェクト 9
  10. 10. Hello World! { val message1 = "Hello" var message2 = "World" message2 += "!" println(message1 + " " + message2) } ブロック式 順 番 に 評 価 最後に評価された式の返り値が ブロック式全体の返り値になる println の 返り値は Unit型 式や文 2018-11-10ゼロから始めるScalaプロジェクト 10
  11. 11. Hello World! def twice(x: Int): Int = { x * 2 } def twice(x: Int): Int = x * 2 式式 {} はあくまでブロック式 メソッド宣言とは無関係 2018-11-10ゼロから始めるScalaプロジェクト 11
  12. 12. 式と文 val result = { val x = 1 + 2 if (x < 0) x else x * 2 } ブロック式 順 番 に 評 価 最後に評価された式の返り値が ブロック式全体の返り値になる 最後に評価された式の返り値が ブロック式全体の返り値になる 6: Int resultには 6が代入される if式 (≒3項演算子) 2018-11-10ゼロから始めるScalaプロジェクト 12 代入文
  13. 13. 式と文 val result = { val x = 1 + 2 if (x < 0) x else x * 2 } 式 文 2018-11-10ゼロから始めるScalaプロジェクト 13
  14. 14. for式 (ループもできる) for {i <- 1 to 3} { println(i) } for {i <- 1 to 3} println(i) val results = for {i <- 1 to 3} i ブロック式 式式 ジェネレータ 1,2,3 から成る数値列の生成 このままでは値を返さな い (): Unit 2018-11-10ゼロから始めるScalaプロジェクト 14
  15. 15. for式 val results1 = for {i <- 1 to 3} yield i val results2 = for { i <- 1 to 5 by 2 j <- 2 to 1 by -1 } yield { val x = i * j x + 1 } yield を付けると値を返す1,2,3 1,3,5 2,1 3,2,7,4,11,6 ジェネレータを 複数並べること で 多重ループ ループに再代入可能な変数は不 要 to: <=, until: <, by: += n 2018-11-10ゼロから始めるScalaプロジェクト 15
  16. 16. match式 val n = 2 val result = n match { case 1 => "1" case 2 | 3 => "2 or 3" case x if x % 2 == 0 => "偶数の" + x.toString case x => s"それ以外の${x}" }上記以外にも 様々な条件を指定可能 対象 定数による条件 OR条件 全てにマッチす るx + 偶数である 全てにマッチする x "2 or 3" 順 番 に 評 価 最初にマッチした 箇所のみ実行され る (break不要) 2018-11-10ゼロから始めるScalaプロジェクト 16
  17. 17. match式 val n = 5 val result = n match { case 1 => "1" case 2 | 3 => "2 or 3" case x if x % 2 == 0 => "偶数の" + x.toString case x => s"それ以外の${x}" }上記以外にも 様々な条件を指定可能 対象 定数による条件 OR条件 全てにマッチす るx + 偶数である 全てにマッチする x "それ以外の5" 順 番 に 評 価 文字列化 式を埋め込み可能な文字列式を埋め込み可能な文字列 2018-11-10ゼロから始めるScalaプロジェクト 17
  18. 18. クラス・オブジェクト・トレイト class Triangle(edges: Array[Int]) { val area = ??? // 省略 def printFigure(): Unit = println("△") } val triangle = new Triangle(Array(3, 4, 5)) println(triangle.area) コンストラクタ引数リ スト フィールドそのもの が コンストラクタにな るインスタンス 化 6.0 ??? は未実装例外のエイリアス 仮にコンパイルを通すのに便利 2018-11-10ゼロから始めるScalaプロジェクト 18
  19. 19. クラス・オブジェクト・トレイト abstract class Polygon(edges: Array[Int]) { val n = edges.size val area: Double def printFigure(): Unit } class Triangle(edges: Array[Int]) extends Polygon(edges) { val area = ??? // 省略 def printFigure(): Unit = println("△") } val triangle = new Triangle(Array(3, 4, 5)) println(triangle.area) 抽象クラ ス 継承 2018-11-10ゼロから始めるScalaプロジェクト 19 +α
  20. 20. クラス・オブジェクト・トレイト abstract class Polygon private(edges: Array[Int]) { val n = edges.size val area: Double def printFigure(): Unit } object Polygon { def fromEdges(edges: Array[Int]): Polygon = edges.size match { case 3 => new Triangle(edges) case 4 => new Square(edges) case n => ??? } } Polygon.fromEdges(Array(3, 4, 5)) オブジェクト (≒staticフィール ド) Triengle 同名のクラスが同一ファイル にあるオブジェクトを コンパニオンオブジェクトと 呼ぶ privateにアクセスできる privateコンストラクタ 2018-11-10ゼロから始めるScalaプロジェクト 20 +α
  21. 21. クラス・オブジェクト・トレイト import java.util.Date trait Tag { val createdDate: Date } trait Color { val rgb: RGB } class TaggedGreenTriangle extends Triangle with Tag with Color { val rbg = new RGB(0, 255, 0) val createdDate = new Date } トレイト: 多重継承可, コンストラクタ引数 なし 抽象クラスに似ている が 一部機能が異なる. どちらも利用できて 迷ったらトレイト インポート (クラス, オブジェクト, メソッ ド等) 別名ミックスイ ン 2つ目以降は with で繋ぐ 2018-11-10ゼロから始めるScalaプロジェクト 21
  22. 22. コレクション・関数 val list1 = (1 to 3).toList val list2 = List(1, 2, 3) val array = Array(1, 2, 3) val odds1 = list1.filter(x => x % 2 == 1) val odds2 = array.filter(x => x % 2 == 1) val sum = list1.sum val twice = list1.map(x => x * 2) val sorted = list1.sorted Range: 範囲から生成されるコレクショ ン 同一I/F List (単方向) に変換 直接 List の初期化 Array (中身はJava配列) 多様な便利API 1,2,31,2,31,2,3 1,31,3 6 2,4,6 1,2,3 2018-11-10ゼロから始めるScalaプロジェクト 22
  23. 23. コレクション・関数 val list = (1 to 3).toList val odds1 = list.filter(x => x % 2 == 1) val selectOdd: Int => Boolean = x => x % 2 == 1 val odds2 = list.filter(selectOdd) 匿名関数のラムダ記 法 匿名関数のラムダ記 法 仮引数仮引数 式式要シグネチャ filterは (T => Boolean) 型を引数に取り各要素で実行 : List[Int] T が Int デフォルトは不変コレクション (Arrayは例 外) import scala.collection.mutable.XXX で可変コレクションも利用可能 2018-11-10ゼロから始めるScalaプロジェクト 23
  24. 24. エラーハンドリング def getData(q: Query): Option[String] = ??? getData(q) match { case Some(str) => println(str) case None => println("該当なし") } Option[T] 抽象クラス Some[T] 単一値を保持 None 値なし 必ずどちらか必ずどちらか match式で場合分け兼Someの場合は値の取り出し 2018-11-10ゼロから始めるScalaプロジェクト 24 データの利用者に データのチェックを強制させる
  25. 25. エラーハンドリング def getNullableString(): String = ??? // 省略 val stringOpt = Option(getNullableString()) stringOpt match { case Some(str) => println(str) case None => println("nullでした") } def throwableMethod(): Int = ??? // 省略 val result = try { throwableMethod() } catch { case ex: Throwable => 0 } try式 式: ブロック 式 match式のように 例外で場合分け式 nullならNone, それ以外ならSome を返す便利メソッド 値な し 単一 値 2018-11-10ゼロから始めるScalaプロジェクト 25 (実際は返り値をOptionにすると良い) +α
  26. 26. エラーハンドリング val list = (1 to 3).toList list.foreach(x => println(x)) def getNullableString(): String = ??? // 省略 val stringOpt = Option(getNullableString()) stringOpt.foreach(str => println(str)) (T => Unit) 型を引数に取り各要素で実行 T が Int コレクションと同じAPIも利用可 能 Noneは長さ0, Someは長さ1の コレクションのように振る舞う 似たようなものとして, 文字列も文字 の コレクションとして扱うことが可能 2018-11-10ゼロから始めるScalaプロジェクト 26
  27. 27. +α 2018-11-10ゼロから始めるScalaプロジェクト 27 +α
  28. 28. 糖衣構文 val x1 = 1 + 2 val x2 = 1.+(2) implicit class MyInt(val x: Int) extends AnyVal { def add(another: Int): Int = x + another } val y1 = 1.add(2) val y2 = 1 add 2 数値を1つ引数に取るIntのメソッ ド Intに「数値を1つ引数に取るメソッ ド」 であるaddを追加 (※詳細省略) 2018-11-10ゼロから始めるScalaプロジェクト 28 等しい 等しい 「引数を1つ取るメソッド」の呼び出 しは 「.」と「()」を省略できる +α
  29. 29. 糖衣構文 class Cat(cry: String) { def apply(postfix: String): Unit = println(cry + postfix) } object Cat { def apply(cry: String): Cat = new Cat(cry) } val cat1 = new Cat("にゃー") val cat2 = Cat("にゃー") val cat3 = Cat.apply("にゃー") cat1("!") cat1.apply("!") 「apply」という名前であればなんでもよ い 2018-11-10ゼロから始めるScalaプロジェクト 29 等しい 「applyという名前のメソッド」の呼び出 しは 「.apply」を省略できる 等しい 配列やリストのインデックス参照が 「()」 でできるのはapplyによるもの +α
  30. 30. クラス class Cat(cry: String) val cat = new Cat("にゃー") // cryはprivateなので外部からアクセスできない class Cat(val cry: String) val cat = new Cat("にゃー") // 宣言にvalを付けると外部からアクセスできる println(cat.cry) 2018-11-10ゼロから始めるScalaプロジェクト 30 publicになる デフォルトはprivate varだと更に 再代入可能に +α
  31. 31. ケースクラス case class Cat(cry: String) val cat1 = new Cat("にゃー") val cat2 = Cat("にゃー") val cat3 = Cat.apply("にゃー") println(cat1.cry) println(cat1.toString) getData(q) match { case Some(str) => println(str) case None => println("該当なし") } 2018-11-10ゼロから始めるScalaプロジェクト 31 コンストラクタ引数と 等しい引数を持つapplyが 自動的に定義されるため, 見かけ上newが不要になる caseを付けるだけ デフォルトでpublic いい感じのtoString コンストラクタ引数 で パターンマッチ可能 unapply (※詳細省略) 通常のclassに便利機能が自動定義される +α

×