Slide 1

Slide 1 text

Scalaで⾃然⽂っぽく コードを書く 2019/05/23 Scala関⻄ × MixLeap

Slide 2

Slide 2 text

⾃⼰紹介 Yohei TSUJI(@crossroad0201) Scalaはエンジニア⼼をくすぐる⾔語です 2

Slide 3

Slide 3 text

Scalaは DSL(※) を作成するための ⾔語仕様が豊富です ので… 3 ※DSL=Domain Specific Language

Slide 4

Slide 4 text

あたかも⾃然⽂の⽂章のように コードを書けます 4

Slide 5

Slide 5 text

百聞は⼀⾒にしかず 5

Slide 6

Slide 6 text

例その1 Scala Testのアサート⽂ 6

Slide 7

Slide 7 text

7 "abc" should have length 3 false should not be true 引⽤:http://www.scalatest.org/user_guide/using_matchers

Slide 8

Slide 8 text

8 new File("test.txt") should be a 'file class Example { def isOrganization: Boolean = true } new Example() should be an 'organization 引⽤:http://www.scalatest.org/user_guide/using_matchers

Slide 9

Slide 9 text

9 Seq("apple", "orange") should contain ("apple") (Seq("A", "B", "C") should contain only ("a", "b", "c")) (after being lowerCased) 引⽤:http://www.scalatest.org/user_guide/using_matchers

Slide 10

Slide 10 text

10 case class Book(title: String, author: String) val book = Book( "Programming in Scala", "Martin Odersky” ) book should have( 'title ("Programming in Scala"), 'author ("Martin Odersky") ) 引⽤:http://www.scalatest.org/user_guide/using_matchers

Slide 11

Slide 11 text

例その2 RESTful APIのルーティング 11

Slide 12

Slide 12 text

12 object WebServer extends HttpApp { override def routes: Route = path("hello") { get { complete(HttpEntity( ContentTypes.`text/html(UTF-8)`, "

Say hello to akka-http

” )) } } } class MinimalHttpApp extends HttpApp { @Override protected Route routes() { return path("hello", () -> get(() -> complete("

Say hello to akka-http

") ) ); } } Scala Java 引⽤: https://doc.akka.io/docs/akka-http/current/routing-dsl/index.html

Slide 13

Slide 13 text

例その3 ⽇本語でも 13

Slide 14

Slide 14 text

14 val 辻 = ユーザー("辻") val Scala関⻄MixLeap = イベント( タイトル = "Scala関⻄×MixLeap", 募集⼈数 = 60 ) 辻 は (Scala関⻄MixLeap に申し込む) match { case 参加できます(_受付票) => println(s"受付票は ${_受付票} です") case 補⽋です(_キャンセル待ち) if _キャンセル待ち.そんなに待てない => _キャンセル待ち をキャンセルする() println("キャンセル待ちが多いので、申込みをキャンセルしました") case 補⽋です(_キャンセル待ち) => println(s"${_キャンセル待ち.待ち⼈数}⼈待ちです") }

Slide 15

Slide 15 text

DSL作成で知っておきたい Scalaの構⽂ 15

Slide 16

Slide 16 text

関数名に記号が使える Scalaでは関数の名前に記号が使えます。 16 class Path(path: String) { def /(child: String): Path = ??? } new Path("foo")./("bar")./("hoge")./("moge") new Path("foo") / "bar" / "hoge" / "moge"

Slide 17

Slide 17 text

レシーバーとメソッドの区切りに 半⾓スペースが使える メソッドを呼び出す場合は、レシーバーとメソッド名の区切りに ピリオドだけでなく半⾓スペースも使えます。 17 class User(name: String) { def renameTo(newName: String) = ??? def bornIn(year:Int, month: Int, day:Int) = ??? } val user = new User("tsuji") user.renameTo("TSUJI") user renameTo "TSUJI" user.bornIn(2019, 5, 20) user bornIn (2019, 5, 20)

Slide 18

Slide 18 text

パラメタ指定時の (…) を省略できる パラメタの数が1つだけメソッドは、パラメタ指定時の (…) を省 略できます。 18 class Greeter(name: String) { def say(greeting: String) = ??? } new Greeter("Tsuji").say("Hello") new Greeter("Tsuji") say "Hello"

Slide 19

Slide 19 text

パラメタを名前指定できる 関数を呼び出す場合などに、 パラメタを パラメタ名=パラメタ値 形式で指定できます。 19 def address( postCode: Option[String] = None, country: String, state: Option[String] = None, prefecture: String, city: String, address: String, building: Option[String] = None ) = ??? address( postCode = Some("999-9999"), country = "Japan", prefecture = "Osaka", city = "Osaka", address = "1-1-1" )

Slide 20

Slide 20 text

{…} でパラメタを渡せる Scalaでは関数にパラメタを渡すときに (…) だけでなく {…} も 使えます。 {…} を使うことであたかも⾔語仕様で⽤意されている構⽂のよ うに関数を使うことができます。 20 trait Transaction def transactional[RESULT](f: Transaction => RESULT): RESULT = ??? transactional(tx => /*処理*/) transactional { tx => // 処理 }

Slide 21

Slide 21 text

既存の型にメソッド追加できる 「Implicit conversion」と呼ばれる機能で、既存の型を修正する ことなくメソッドを追加(したかのように⾒せる)できます。 ※ただし乱⽤しないように!! 21 implicit class GreetableString(value: String) { def sayHello: String = s"Hello $value” } "World" sayHello

Slide 22

Slide 22 text

まとめ • Scalaは⾔語仕様レベルでDSLが考慮されており、 ⾃然な表現のDSLを作成することができます。 • 業務アプリケーションでも、うまくDSLを作ることが 可読性の⾼いコードを記述する助けになるはずです。 • ドメイン駆動設計を採⽤している場合は、ドメイン モデルをDSLにすることで、ユースケースを⾃然⽂ のように書けます。 22

Slide 23

Slide 23 text

ご清聴ありがとうございました 23