Upgrade to Pro — share decks privately, control downloads, hide ads and more …

明日から業務で使うScala

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 明日から業務で使うScala

Avatar for Ikuo Suyama

Ikuo Suyama

March 21, 2017
Tweet

More Decks by Ikuo Suyama

Other Decks in Programming

Transcript

  1. ͓࿩͢Δ͜ͱ ˕  νϡʔτϦΞϧͰڭ ͑ͯ͘Εͳ͍ʢग़ͯ ͖ͯ΋αϥοͱ…ʣ ͚Ͳݱ࣮ੈքͰ໾ཱ ͭScala ˕  ۀ຿Ͱ࢖͍࢝Ίͨࠒ ʹࠔͬͨ΋ͷɾૣ͘

    ஌͓͖͔ͬͯͨͬͨ Scala ◦ ʮ͋ͷ࣌ΞϨΛ஌͍ͬͯ Ε͹…ʯ ຊ೔ͷςʔϚ ۀ຿Ͱ࢖͏Scala ͓࿩͠ͳ͍͜ͱ ˕  ͳͥScalaΛ࢖͏͔ɺ ਓྨ͸ScalaͰ޾ͤ ʹͳΕΔ͔ ˕  object, traitͳͲجૅ తͳจ๏ͷ࿩ ˕  M͔Β͸͡·Δ΍ͭ ͱؔ਺ܕͷ࿩
  2. IDE

  3. υఆ൪Emacs࢖͍ͷํΰϝϯφαΠ… Scala։ൃͰศརͳػೳ IDE: IntelliJ + Scala Plugin ˕  γϣʔτΧοτ ◦ 

    ^ + Shift + P : ܕ৘ใ ◦  ⌘ + B/⌘ + ^ + B : ఆٛɺ࣮૷Jump ◦  Alt + Enter : ͳΜͰ΋मਖ਼ ◦  Shift x2: ͳΜͰ΋ݕࡧ , etc… “ ๩͍͠ਓͷͨΊͷIntelliJ IDEAγϣʔτΧοτूʢ´-`ʣ ˕  ScalaWorkSheet ◦  New -> Scala Worksheet ◦  IDEΤσΟλػೳ͕࢖͑ΔREPL ◦  ͪΐͬͱෳࡶͳίʔυͷݕূʹ࢖͏
  4. ఆ൪Ϗϧυπʔϧ ͪΐͬͱ΍΍͍͜͠… SBT organization := "io.martin.lover” version := "0.1.0” scalaVersion

    := "2.12.1” libraryDependencies ++= Seq ( "org.specs2" %% "specs2-core" % "3.8.9" % "test” ) !? !? !?
  5. ͜Ε͚֮ͩ͑Δ ˕  build.sbt͸Scalaͱͯ͠ίϯύΠϧ͞ΕΔ ◦  Scalaίʔυ͕ॻ͚Δɻval, lazy val, def ͕࡞ΕΔ ‒ object,

    class͸τοϓϨϕϧʹ͸࡞Εͳ͍ ◦  ݟ֮͑ͷͳ͍ه߸͸⌘+B౳ͰఆٛΛ୳ΕΔ ˕  build.sbt DSL ◦  `:=` … ࠨล(setting/task key)ʹӈลͷ݁ՌΛઃఆ͢Δ ◦  `+=` … ࠨลʹӈลͷ݁ՌΛ௥Ճ͢Δ ◦  `++=` … ࠨลʹӈลͷ݁ՌΛෳ਺Ұ౓ʹ௥Ճ͢Δ SBT
  6. SBT: Setting/Task “SBT-Ϗϧυఆٛ ˕  ࠨลɿΩʔ ◦  SettingKey[T] αϒϓϩδΣΫτಡΈࠐΈ࣌ɺҰ౓͚ͩܭࢉ ◦  TaskKey[T]

    ຖճܭࢉɻ෭࡞༻Λ൐͏Մೳੑ͋Γ ˕  ΦϖϨʔλʔɿϚΫϩ ˕  ӈลɿຊจ ◦  ઃఆ͢Δ஋
  7. SBT: Libraly Dependencies “SBT-ϥΠϒϥϦґଘੑ libraryDependencies += ”groupID” %% ”artifactID” %

    ”revision" % ”configuratioin" ◦  ґଘ؅ཧ͸Apache Ivy ɺMavenͱಉ͡ײ֮Ͱ͔ͭ͑Δ ◦  σϑΥϧτͰMavenͷpublicRepΛ୳͢ libraryDependencies ++= Seq ( "commons-daemon" % "commons-daemon" % "1.0.15", "org.specs2" %% "specs2-core" % "3.8.9" % "test” excludeAll ExclusionRule(organization = "log4j") ) 特定のライブラリを弾きたいことが 稀によくある ◦  %% ͸scalaVersionΩʔͰఆٛͨ͠ScalaͷόʔδϣϯʢΫ ϩεϏϧυʣͷόΠφϦΛ୳͢ ◦  scalaVersion := “2.12.1“ͱͨ͠৔߹͸ “_2.12“ ΛartifactIDʹ ิ͏͚ͩɻ↑ͷྫͰ͸ “secs2-core_2.12“ Λ୳͢ javaライブラリは`%` Scalaビルドがあるときは`%%`
  8. SBT: Multi Projects “SBT−ϚϧνϓϩδΣΫτ lazy val `core` = (project in

    file("core")) lazy val `web` = project ◦  ڞ௨Ϟσϧ΍Util ͷ੾Γग़͠౳ɺෳ਺ͷҟଘͷ͋Δϓϩδ ΣΫτΛ࡞Γ͍ͨͱ͖ʢ΄ͱΜͲຖճ…ʣ ◦  project ͸ϚΫϩͰɺม਺໊ΛIDʹͨ͠Projectܕͷ஋Λ࡞੒ ͢Δ ◦  IDͱσΟϨΫτϦ͕ಉ࣌͡͸লུͰ͖Δ
  9. SBT: Multi Projects Sample “αϯϓϧ – ϑϧ൛ lazy val commonSettings

    = Seq( organization := "io.martin.lover", version := "0.1.0", scalaVersion := "2.12.1" ) lazy val `root` = (project in file(".")) .aggregate(`core`, `web`) lazy val `core` = (project in file("core")) .settings(commonSettings) lazy val `web` = (project in file("web")) .settings(commonSettings) .settings(libraryDependencies ++= webLibraryDependencies) .dependsOn(core) lazy val webLibraryDependencies = Seq(/* ... */) $ sbt sbt> project core サブプロジェクト切り替え。 初回時自動で必要なデレィクトリが 作成される 集約。 集約される側(core, web)で 同じタスクを実行。 依存。 依存される側(core)で 同じタスクを先に実行 &クラスパスに読み込み
  10. লུ val list = Seq(1, 2, 3, 4, 5) list

    map { i => i + 1 } わかる !!? ˕  ஌ͬͯͳ͍ͱಡΊͳ͍ܗ͕ଟ͍ɺɺ ˕  ༰ࣻͳ͘ϥΠϒϥϦͷνϡʔτϦΞϧ౳Ͱग़ ͯɺDSLͱݟ෼͚͔ͭͳͯ͘ࠔͬͨ ˕  සग़ͷܗΛPickupͯ͠঺հ͠·͢ɻ ◦  ͋ͱ͸ग़͖ͯͨͱ͖ʹؤுΔ “Scala ͷলུϧʔϧૣ֮͑ “ScalaͰͷϝιουݺͼग़͠ͷॻ͖ํҰཡͱਪ঑͞ΕΔॻ͖ํ
  11. লུ: ϥϜμࣜ val list = Seq(1, 2, 3, 4, 5)

    def double(i: Int): Int = { i * 2 } list.map(double) val double:(Int) => Int = (i: Int) => i * 2 list.map(double) ◦  double͸ී௨ͷؔ਺ఆٛɻmap͸Ҿ਺̍ͭͷؔ਺ΛҾ਺ʹ औΔߴ֊ؔ਺ɻ 関数型定義 のS.S. Function1のインスタンス =無名関数=ラムダ式 ◦  ؔ਺ఆٛͷলུɻFunction1ܕͷม਺ͱͯ͠ॻ͚Δɻӈล͸ ϥϜμࣜͱݺ͹ΕΔ
  12. লུ: தஔه๏ val list = Seq(1, 2, 3, 4, 5)

    val double2:(Int) => Int = (i: Int) => i * 2 list.map(i => i * 2) list map { i => i * 2 } ◦  Ҿ਺ͷܕ͕ࣗ໌ͷ৔߹ɺҾ਺ܕΛলུͯ͠Α͍ ◦  Ҿ਺͕̍ͭͷ৔߹ɺ()Λলུͯ͠ྑ͍ : Int と () を省略 list map {_ * 2} ◦  . ͱ () ͷলུʢதஔه๏ʣ ◦  ؔ਺ΛҾ਺ʹ̍ͭऔΔ৔߹ɺ() ͷ୅ΘΓʹ {} Λ࢖ͬͯྑ͍ この形が頻出! ◦  ͢΂ͯͷҾ਺͕̍ճ͔͠࢖ΘΕͳ͍৔߹ɺҾ਺ఆٛΛলུ ͯ͠ `_` ʹͰ͖Δ(!) _ は一つ目の引数、の意。頻出!!
  13. ϥΠϒϥϦʹݟΔதஔه๏ val name = "martin.lover" val memberId: Option[Long] = DB

    readOnly { implicit session => sql"select id from members where name = ${name}" .map(rs => rs.long("id")) .single .apply() } scalikeJDBC "Specs2" should { "use infix notation" in { "test" mustEqual "test" } } specs2 val route: Route = get { pathPrefix("item" / LongNumber) { id => // there might be no item for a given id val maybeItem: Future[Option[Item]] = fetchItem(id) akka-http should, inが高階関数 () => Flagment readOnly が高階関数 DBSession => A pathPrefixが高階関数 Directive1
  14. For Comprehension val maybeName: Option[String] = Some("martin.lover") val maybeAge: Option[Int]

    = Some(33) case class Person(name:String, age:Int) val person: Option[Person] = for { name <- maybeName age <- maybeAge } yield Person(name, age) わかる !!? ˕  ֮͑Δͱ͍͢͝ศརˍڧྗ ˕  ੍ޚΛ௥Θͳͯ͘ྑ͘ͳΔͷͰɺՄಡੑ↑↑ ◦  ޷Έ͸͋Δͱࢥ͍·͢ɻɻLODEOͰ͸සग़ɻ わかる “ Scalaεέʔϥϒϧϓϩάϥϛϯά(ίοϓຊ) 23ষ forࣜͷ࠶આ
  15. For Comprehension: ల։ val maybeName: Option[String] = Some("martin.lover") val maybeAge:

    Option[Int] = Some(33) val person: Option[Person] = for { name <- maybeName age <- maybeAge } yield Person(name, age) val person: Option[Person] = maybeName flatMap { name => maybeAge map { age => Person(name, age) } } ◦  `<-` ͸δΣωϨʔλʔͱݺ͹ΕΔ ◦  flatMap ͱ͔ map ͱ͔ foreach ͱ͔ withFilter ʹల։͞ΕΔ なるほど わからん
  16. For Comprehension: ֮͑ํ val person: Option[Person] = for { name

    <- maybeName age <- maybeAge addr <- maybeAddr } yield Person(name, age) Forを始めた外側の 型が最後まで続く Option[String] 外側剥がれる name:String 外側の型を 揃える Option[T] 中はなんでも良い 計算失敗したら それ以上実行 しない 最後まで成功したら 外側の型でくるんで返す ◦  flatMap, map͕࣮૷͞Ε͍ͯΕ͹ɺ͜͜Ͱ͍͏ʮ֎ଆͷܕʯ ͱͯ͠࢖͑Δʹʮจ຺෇͖ͷܕʯ ◦  ্ͷྫͳΒɺmaybeName,maybeAge,maybeAddr͕͢΂ͯ SomeͳΒ Some(Person), ͲΕ͔NoneͳΒNone͕ฦΔ
  17. For Comp~: ͏Ε͍͜͠ͱ maybeName match { case Some(name) => maybeAge

    match { case Some(age) => maybeAddr match { case Some(addr) => Person(name, age) case None => None } case None => None } case None => None } (maybeName, maybeAge, maybeAddr) match { case (Some(name), Some(age), Some(addr)) =>     Some(Person(name, age)) case _ => None } ◦  ͜͏͍͏ίʔυ͕ݟ΍͘͢վળͰ͖Δ ◦  matchͷωετΛݟͨΒforจͰॻ͖׵͑ΔϓϧϦΫνϟϯεʂ どこで終わるの、、、 ()多すぎ、、
  18. For Comp~: Either flatMap def validateName(name: String): Either[String, String] def

    validateAge(age: Int): Either[String, Int] val validPerson = for { name <- maybeName toRight "Name is Required" age <- maybeAge toRight "Age is Required" _ <- validateName(name) _ <- validateAge(age) } yield Person(name, age) ◦  Eitherͷྫɻෳ਺ॏͳΔͱmatchωετ͕ͪ͠ ◦  Scala 2.12 Ͱ Either ͕ Right-Biasʹͳͬͨʂʂ ‒ .rightΛॻ͔ͳͯ͘ྑ͘ͳͬͨ Eitherを返したいので、 OptionをEitherに変換して Eitherでforを始める Eitherの検証のみで値を 利用しないときは _ で受ける “ଞͷܕͰͷαϯϓϧ
  19. Config libraryDependencies ++= Seq ( "com.typesafe" % "config" % "1.3.1"

    ) server { host = "localhost" port = 8080 } import com.typesafe.config.ConfigFactory val config = ConfigFactory.load val host = config.getString("server.host") val port = config.getString("server.port") println(s"server start: http://${host}:${port}”) ◦  جຊ TypesafeConfig ͰࠔΒͳ͍ɻଟ͘ͷϥΠϒϥϦͰར༻ ◦  Developmet / Staging / Producion Ͱ஋Λ੾Γସ͍͑ͨ build.sbt resources/application.conf Hoge.scala この名前のファイルは デフォルトで読み込まれる
  20. Config੾Γସ͑ include "application.conf" server { host = ”unit.test.io" } ◦ 

    UT༻͸ test/resources/ʹஔ͚ͩ͘ɻઃఆͨ͠΋ͷ্͚ͩॻ͖ ◦  ؀ڥ੾Γସ͑ʹ͸֤؀ڥຖʹͦΕͧΕϑΝΠϧΛ४උ͠ɺJVM OptionͰ౉͢ͷ͕ʢ͓ͦΒ͘ʣ࠷΋؆୯ test/resources/application.conf include "application.conf" server { host = "martin.lover.io" } resources/production.conf $ java –Dconfig.resource=production.conf -jar martin_lover_io.jar $ java –Dconfig.file=/path/to/your/resources/production.conf application.confをincludeし、 producion.confで記載したものだけ上書きする 起動時にJVMオプションで読み込むファイルを指定 config.fileでクラスパス外ファイルも指定可能
  21. ύοέʔδ: sbt-native-packager lazy val `web` = (project in file("web")) :

    .enablePlugins(JavaServerAppPackaging) build.sbt “sbt-native-packager addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.4") project/plugins.sbt ◦  sbt-assemblyΛΑ͘ར༻͍ͯ͠Δ͕ɺͪ͜Β͸ΑΓଟػೳ ◦  ىಈεΫϦϓτ͕࡞ΕΔɻDockerImage ΍ (࢖Θͳ͍ͱࢥ͏ ͕)msi, dmg ΋࡞ΕΔ
  22. lazy val `web` = (project in file("web")) : .settings(buildSettings) .enablePlugins(JavaServerAppPackaging)

    .enablePlugins(SystemVPlugin) .enablePlugins(RpmPlugin) build.sbt “build.sbtͷ׬શͳαϯϓϧ `Archetypes` サーバー起動 `Systemloaders` `Formats` ◦  SystemloadersΛࢦఆ ‒ CentܥͰ /etc/init.d ͷεΫϦϓτ͕΄͍͠ͱ͖͸SystemV ◦  RpmϏϧυΛ࡞੒͢Δ͜ͱΛએݴ ‒ UniversalϏϧυͰ͸ϓϥοτϑΥʔϜґଘͷϑΝΠϧ͸࡞੒͞Εͳ͍ $ sbt sbt> project web [web] > rpm:packageBin ύοέʔδ: sbt-native-packager