Ipros techmeetup 20131218_scala_handson

Post on 30-Jun-2015

1.969 views 0 download

description

2013/12/18に株式会社イプロスにて開催されたScalaハンズオン勉強会の後半パートで使用したスライドです。

Transcript of Ipros techmeetup 20131218_scala_handson

未経験者のための Scala

株式会社イプロス 本多陽平

2 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

後半パート

Scala の真髄に少しだけ触れる

3 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

自己紹介

• 本多陽平

• 2012 年 2 月イプロス入社

• Java 歴 1 年半→ Scala 歴半年

• 現在は広告系サービスの開発を担当

• 去年登山を始めました

• サッカーを観たり、梅干しをつけたり、温泉に行ったり、が趣味

4 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

後半パートについて

後半パートでは、 Scala の• オブジェクト指向要素• 関数プログラミング要素の両側面に簡単に触れるとともに、SBT を使ったビルドについても触れます。

5 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

アジェンダ1. Scala でオブジェクト指向

1. クラスハンズオン

2. トレイト2. Scala で関数プログラミング

1. 高階関数ハンズオン

3. SBT によるビルド1. コンパイル

ハンズオン2. 実行

ハンズオン3. パッケージング

ハンズオン

6 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

前置き

Scala の言語仕様を網羅的に説明しているわけではないので、ご了承下さい

7 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

サンプルコードについて

後半パートで使用するサンプルコードは以下にアップロードしてあります。

イプロス開発ブログhttp://ipros-creators.tumblr.com/※ 「イプロス 開発」で検索

8 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

オブジェクト指向要素編

Scala でオブジェクト指向

9 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス

Scala は関数型言語であり、オブジェクト指向言語でもあるので、クラスを使えます

10 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

クラス定義

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

C-1

11 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ > 基本コンストラクタ

インスタンスが生成される度に呼ばれます

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

C-1

12 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ > クラスパラメータ

クラスパラメータは基本コンストラクタのパラメータとなります

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

C-1

13 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ > 補助コンストラクタ

this キーワードをつけると、補助コンストラクタとなります

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

※ 必ず初めに基本コンストラクタを呼ぶ必要がある

C-1

14 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

基本コンストラクタでインスタンス生成

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

scala> val fuji = new Mountain("Fuji")fuji: Mountain = Mountain@23e9436c

C-1

15 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

名前は?

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

scala> val fuji = new Mountain("Fuji")fuji: Mountain = Mountain@23e9436c

scala> fuji. tab キーで補完

C-1

16 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

名前は?

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

scala> val fuji = new Mountain("Fuji")fuji: Mountain = Mountain@23e9436c

scala> fuji.asInstanceOf isInstanceOf printName toString

↑ 可視性はデフォルトで Public

C-1

17 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

名前は?

scala> fuji.asInstanceOf isInstanceOf printName toString

scala > fuji.printNameres0: String = Mt. Fuj

C-1

18 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

補助コンストラクタでインスタンス生成

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

scala> val nanashi = new Mountain()nanashi: Mountain = Mountain@233a4b09

C-1

19 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

名前のない山ができました

scala> class Mountain (name: String) { | val printName = "Mt. " + name | def this() = { | this("Unknown") } }defined class Mountain

scala> val nanashi = new Mountain()nanashi: Mountain = Mountain@233a4b09

scala> nanashi.printNameres0: String = Mt. Unknown

C-1

20 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

クラスパラメータがフィールドにありません

scala> fuji.asInstanceOf isInstanceOf printName toString

C-1

21 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

val をつけて定義するとフィールドになります

scala> class Mountain (val name: String)defined class Mountain

C-2

22 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

name にアクセスできました

scala> class Mountain (val name: String)defined class Mountain

scala> val fuji = new Mountain("Fuji")fuji: Mountain = Mountain@55a4221f

scala> fuji.asInstanceOf isInstanceOf name toString

scala> fuji.nameres1: String = Fuji

C-2

23 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > コンストラクタ

1. 基本コンストラクタ

2. 補助コンストラクタ

3. クラスパラメータ1. フィールド指定なし

2. フィールド指定あり

ここまでのまとめ

class Mountain { val name = "Fuji" }

class Mountain (name: String)

class Mountain (val name: String)

class Mountain (val name: String) { def this() = { this("Unknown") }}

24 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > メソッド

メソッド

25 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > メソッド

メソッド定義は簡単で、関数定義と同じです

scala> class Mountain (val name: String) { | def erupt = { println("erupted!") }}defined class Mountain

※ 呼び方(ということが多いです) 関数単体 = 関数 クラス内の関数 = メソッド

C-3

26 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > メソッド

呼び出し

scala> class Mountain (val name: String) { | def erupt = { println("erupted!") }}defined class Mountain

scala> val vesuvius = new Mountain("Vesuvius")vesuvius: Mountain = Mountain@6f9c2c4

scala> vesuvius.erupterupted!

C-3

27 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > ハンズオン

噴火する度に標高が下がる山

を作ってみましょう

28 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > ハンズオン > コーディング例

こんな感じ

scala> class Mountain (val name: String, var alt: Int) { | def erupt = { | alt -= 100 | println("erupted! alt = " + alt) }}defined class Mountain

29 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

クラス > ハンズオン > コーディング例 > 動作確認

動かしてみましょう

scala> class Mountain (val name: String, var alt: Int) { | def erupt = { | alt -= 100 | println("erupted! alt = " + alt) }}defined class Mountain

scala> val vesuvius = new Mountain("Vesuvius", 1281)vesuvius: Mountain = Mountain@4e3ecc02

scala> vesuvius.erupterupted! alt = 1181

scala> vesuvius.erupterupted! alt = 1081

← 下がってる

← 下がってる

30 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト

実装の定義も可能な Java のインターフェース

という感じです

31 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト

trait キーワードをつけて定義します

scala> trait Mountain { | def getName: String | def getAlt: Int | def getInfo = { | println(getName + getAlt) }}defined trait Mountain

T-1

32 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト

メソッド宣言

scala> trait Mountain { | def getName: String | def getAlt: Int | def getInfo = { | println(getName + getAlt) }}defined trait Mountain

T-1

33 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト

メソッド定義

scala> trait Mountain { | def getName: String | def getAlt: Int | def getInfo = { | println(getName + getAlt) }}defined trait Mountain

T-1

34 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 具象クラス

extends して作ります = ミックスイン

scala> trait Mountain { | def getName: String | def getAlt: Int | def getInfo = { | println(getName + getAlt) }}defined trait Mountain

scala> class Fuji extends Mountain { | def getName = "Fuji" | def getAlt = 3776 }defined class Fuji

T-2

35 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 具象クラス

こうした方が親切です( Scala 文化的にはつけないようですが)

scala> class Fuji extends Mountain { | override def getName = "Fuji" | override def getAlt = 3776 }defined class Fuji

T-3

36 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 抽象フィールド

val をつけてフィールド宣言

scala> trait Mountain { | val name: String | val alt: Int | def getInfo = { | println(name + alt) }}defined trait Mountain

T-4

37 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 抽象フィールド > 具象クラス

具象クラスの作成

scala> trait Mountain { | val name: String | val alt: Int | def getInfo = { | println(name + alt) }}defined trait Mountain

scala> class Fuji extends Mountain { | val name = "Fuji" | val alt = 3776 }defined class Fuji

T-5

38 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト

トレイトは複数ミックスインできます

39 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 複数トレイトのミックスイン

1 つ目のトレイト

scala> trait Mountain { | val name: String | val alt: Int | def getInfo = { | println(name + alt) }}defined trait Mountain

T-6-1

40 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 複数トレイトのミックスイン

2 つ目のトレイト

scala> trait Mountain { | val name: String | val alt: Int | def getInfo = { | println(name + alt) }}defined trait Mountain

scala> trait Volcano { | def erupt() { println("erupted!") }}defined trait Volcano

T-6-2

41 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 複数トレイトのミックスイン

これらをミックスインすると、

scala> class Shinmoe extends Mountain with Volcano { | val name = "ShinmoeDake" | val alt = 1421 }defined class Shinmoe

↑2 つ目からは with

T-6-3

42 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > 複数トレイトのミックスイン

それぞれの特性を持ったクラスを作ることができます

scala> class Shinmoe extends Mountain with Volcano { | val name = "ShinmoeDake" | val alt = 1421 }defined class Shinmoe

scala> val shinmoe = new Shinmoeshinmoe: Shinmoe = Shinmoe@1b827696

scala> shinmoe.altres2: Int = 1421

scala> shinmoe.erupterupted!

T-6-3

43 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

トレイト > まとめ

1. メソッドもフィールドも抽象化できる

2. 複数のトレイトをミックスインすることができる

Scala には抽象クラスもありますが、基本トレイトで事足ります

trait Mountain { def getName: String val alt: Int }

class Shinmoe extends Mountain with Volcano { val name = "ShinmoeDake" val alt = 1421 }

44 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

オブジェクト指向要素編 > まとめ

Java と文法が異なり、また Java にはないトレイトという概念が存在しますが、 Java と大きく異なる点はありません。

45 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

オブジェクト指向要素編 > まとめ

JDK 8 にはトレイトに似た機能として仮想拡張メソッド( Virtual Extension Methods )が追加される予定です

46 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数プログラミング要素編

Scala で関数プログラミング

47 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

高階関数とは

48 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

パラメータとして関数を取ったり、関数を返す関数

49 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

高階関数の定義

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

FH-1

50 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

execFunc というこの関数は

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

FH-1

51 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

Int 型の引数を受け取り

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

FH-1

52 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

Boolean を返します

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

FH-1

53 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

exec は execFunc を呼びます

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

FH-1

54 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

execFunc の定義

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

scala> def isZero(num: Int) = { | if (num == 0) true else false }isZero: (num: Int)Boolean

FH-1

55 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

使ってみましょう

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

scala> def isZero(num: Int) = { | if (num == 0) true else false }isZero: (num: Int)Boolean

scala> exec(0, isZero)res1: Boolean = true

FH-1

56 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数

使ってみましょう

scala> def exec(num: Int, execFunc: Int => Boolean) = { | execFunc(num) }exec: (num: Int, execFunc: Int => Boolean)Boolean

scala> def isZero(num: Int) = { | if (num == 0) true else false }isZero: (num: Int)Boolean

scala> exec(0, isZero)res1: Boolean = true

scala> exec(1, isZero)res2: Boolean = false

FH-1

57 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

文字列をフィルタする関数を実行し、フィルタの結果を表示する高階関数

を作ってみましょう

関数 > 高階関数 > ハンズオン

58 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > ハンズオン > コーディング例

高階関数

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

59 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > ハンズオン > コーディング例

フィルタ関数

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> def lengthFilter(str: String) = { | if (str.length > 10) true | else false }lengthFilter: (str: String)Boolean

60 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > ハンズオン > コーディング例

動作確認

scala> filterBy(" 明日は晴れると良いな ", lengthFilter)not

scala> filterBy(" 明日は雲ひとつない晴天となるでしょう ", lengthFilter)passed

61 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

同じ文字列に対していろんなフィルタをかけたい時

関数 > 高階関数 > カリー化

62 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

高階関数

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

FH-2

63 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

を、カリー化してみる

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> val curriedFilterBy = (filterBy _).curriedcurriedFilterBy: String => ((String => Boolean) => Unit) = <function1>

※カリー化複数の引数を取る関数を、ある引数 xを取り残りの引数を取る関数に変換すること

FH-2

64 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

curriedFilterBy は String 型の引数を取り、

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> val curriedFilterBy = (filterBy _).curriedcurriedFilterBy: String => ((String => Boolean) => Unit) = <function1>

FH-2

65 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

String 型の引数から Boolean 型の結果を返す関数を返しますよ

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> val curriedFilterBy = (filterBy _).curriedcurriedFilterBy: String => ((String => Boolean) => Unit) = <function1>

FH-2

66 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

パラメータを 1 つしか指定してなくても呼べます

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> val curriedFilterBy = (filterBy _).curriedcurriedFilterBy: String => ((String => Boolean) => Unit) = <function1>

scala> curriedFilterBy("1234567890")res19: (String => Boolean) => Unit = <function1>

※部分適用引数の一部だけを関数に適用すること

FH-2

67 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化

lengthFilter を渡すと、フィルタ結果が表示されます

scala> def filterBy(str: String, filter: String => Boolean) = { | if (filter(str)) println("passed") | else println("not") }filterBy: (str: String, filter: String => Boolean)Unit

scala> val curriedFilterBy = (filterBy _).curriedcurriedFilterBy: String => ((String => Boolean) => Unit) = <function1>

scala> curriedFilterBy("1234567890")res19: (String => Boolean) => Unit = <function1>

scala> curriedFilterBy("1234567890")(lengthFilter)not

FH-2

68 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

文字列フィルタを追加し、カリー化した先ほどの高階関数を使ってフィルタしてみましょ

関数 > 高階関数 > カリー化 > ハンズオン

69 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化 > ハンズオン > コーディング例

フィルタ関数

scala> def matchingFilter(str: String) = { | if (str.contains("scala")) true | else false }matchingFilter: (str: String)Boolean

70 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化 > ハンズオン > コーディング例

フィルタ対象文字列まで部分適用した関数オブジェクトを作り

scala> def matchingFilter(str: String) = { | if (str.contains("scala")) true | else false }matchingFilter: (str: String)Boolean

scala> val func = curriedFilterBy("Scala は面白い言語です ")func: (String => Boolean) => Unit = <function1>

71 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化 > ハンズオン > コーディング例

フィルタにかけてみます

scala> def matchingFilter(str: String) = { | if (str.contains("scala")) true | else false }matchingFilter: (str: String)Boolean

scala> val func = curriedFilterBy("Scala は面白い言語です ")func: (String => Boolean) => Unit = <function1>

scala> func(lengthFilter)passed

72 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

関数 > 高階関数 > カリー化 > ハンズオン > コーディング例

フィルタにかけてみます

scala> def matchingFilter(str: String) = { | if (str.contains("scala")) true | else false }matchingFilter: (str: String)Boolean

scala> val func = curriedFilterBy("Scala は面白い言語です ")func: (String => Boolean) => Unit = <function1>

scala> func(lengthFilter)passed

scala> func(matchingFilter)not

73 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

高階関数と同様の機能が JDK 8 には搭載される予定です

関数編 > さいごに

74 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT 編

SBT

75 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT 編

目的• SBT の簡単な説明• ビルド定義ファイルを書いてみる• jar ファイルを作る

76 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > 概要

• コンパイル• 実行• テスト• パッケージング• ライブラリ管理などを行えます。プラグインで機能拡張が可能です。

SBT とは Java, Scala 向けビルドツールです (SBT = Simple Build Tool)

77 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > 概要

• コンパイル• 実行• テスト• パッケージング• ライブラリ管理

今回は以下を取り上げます

78 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > 構成要素

1. SBT 本体 → インストール済み

2. Scala ソースコード → 以降で紹介

3. ビルド定義ファイル → 以降で紹介

SBT を利用する場合最低限必要なもの

79 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > 構成要素 > ディレクトリ構成

SBT プロジェクトのディレクトリ構成

src/ main/ resources/ リソースファイルディレクトリ scala/ Scala ソースファイルディレクトリ java/ Java ソースファイルディレクトリ test/ resources/ リソースファイルディレクトリ scala/ Scala ソースファイル java/ Java ソースファイル

※src配下にある上記以外のディレクトリは無視されます

80 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル

1. build.sbt

ビルド定義ファイルは 2種類あります

2. Build.scala

• シンプルなビルド定義であればこちらで OK• 各設定は 1 行あけて記述する

• build.sbt で事足りない場合にはこちらを使う• Scala のコードをそのまま書くことができる

81 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル

1. build.sbt

今回はこちらを取り上げます

2. Build.scala

• シンプルなビルド定義であればこちらで OK• 各設定は 1 行あけて記述する

• build.sbt で事足りない場合にはこちらを使う• Scala のコードをそのまま書くことができる

82 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル > build.sbt

サンプル

name := "hello"

version := "1.0"

scalaVersion := "2.10.3"

83 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル > build.sbt

プロジェクトの名前です

name := "hello"

version := "1.0"

scalaVersion := "2.10.3"

84 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル > build.sbt

プロジェクトのバージョンです

name := "hello"

version := "1.0"

scalaVersion := "2.10.3"

85 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ビルド定義ファイル > build.sbt

使用する Scala のバージョンです

name := "hello"

version := "1.0"

scalaVersion := "2.10.3"

86 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

任意のディレクトリ配下に以下のファイルを作成します

name := "hello"

version := "1.0"

scalaVersion := "2.10.3"

1. build.sbt

2. Hello.scalaobject Main { def main(args: Array[String]): Unit = { println("Hello") }} ※object = シングルトンオブジェクト

S-1

S-2

87 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

ディレクトリ構成

src/ build.sbt main/ scala/ Hello.scala

S-3

88 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

SBT を起動してまずはコンパイル

$ cd /path/to/project

$ sbt[info] Set current project to sbt (in build file:/path/to/project)> compile

89 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

コンパイルされました

$ cd /path/to/project

$ sbt[info] Set current project to sbt (in build file:/path/to/project)> compile[info] Updating {file:/path/to/project/}sbt...[info] Resolving org.fusesource.jansi#jansi;1.4 ...[info] Done updating.[info] Compiling 1 Scala source to /path/to/project/target/scala-2.10/classes...[success] Total time: 1 s, completed 2013/12/10 19:57:20>

90 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

続いて実行してみます

> run

91 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン①

実行結果

> run[info] Running Main Hello[success] Total time: 0 s, completed 2013/12/10 19:59:30>

← 表示された!

92 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン②

パッケージングも簡単です

> package

93 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン②

実行結果

> package[info] Packaging /path/to/project/target/scala-2.10/sbt_2.10-1.0.jar ...[info] Done packaging.[success] Total time: 0 s, completed 2013/12/10 20:01:37

← できた!

94 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン②

java コマンドで実行してみます

> package[info] Packaging /path/to/project/target/scala-2.10/sbt_2.10-1.0.jar ...[info] Done packaging.[success] Total time: 0 s, completed 2013/12/10 20:01:37> exit$ ls$ build.sbt project src target$ cd target/scala-2.10/$ lsclasses sbt_2.10-1.0.jar$ java -cp ./sbt_2.10-1.0.jar:/path/to/scala-library.jar Hello

※ホームディレクトリ /.sbt配下にあるはず

95 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン②

実行結果

> package[info] Packaging /path/to/project/target/scala-2.10/sbt_2.10-1.0.jar ...[info] Done packaging.[success] Total time: 0 s, completed 2013/12/10 20:01:37> exit$ build.sbt project src target$ cd target/scala-2.10/$ lsclasses sbt_2.10-1.0.jar$ java -cp ./sbt_2.10-1.0.jar:/path/to/scala-library.jar HelloHello

96 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン③

package で生成する jar ファイル名を

scala-handson_2.10-9.9.jarに変えてみましょう

97 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン③ > 設定例

build.sbt を変えます

name := "scala-handson"

version := "9.9"

scalaVersion := "2.10.3"

98 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > ハンズオン③ > 設定例 > 実行結果

変わっていますね

> package[info] Packaging /path/to/project/target/scala-2.10/scala-handson_2.10-9.9.jar ...[info] Done packaging.[success] Total time: 0 s, completed 2013/12/10 20:25:17

99 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > プラグイン

• sbt-eclipse (https://github.com/typesafehub/sbteclipse)

• Eclipse のプロジェクトファイルを生成できる

• xsbt-web-plugin (https://github.com/JamesEarlDouglas/xsbt-web-plugin)

• Web 開発用のプラグイン

• sbt-assembly (https://github.com/sbt/sbt-assembly)

• オールインワンの jar ファイルを生成できる

色々と便利なプラグインがあります

100 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

SBT > プラグイン

プラグインを利用すれば、大抵のことはできます。イプロスでは Jenkins と併せて、ビルド、 DBマイグレーション、デプロイまでをSBT で実施しています。

101 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

まとめ

まとめ

102 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

まとめ

イプロスでは広告系システムの開発に Scalaを導入し、 REST API サービス及びバッチを開発しています。

Scala の持つ概念の一部が JDK 8 でも取り入れられる予定であることから、今日ご紹介した内容は今後当たり前になっていくと思います。

103 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

まとめ

この勉強会が Scala を学ぶ契機となったならば幸いです。

104 COPYRIGHT © 2013 IPROS CORPORATION ALL RIGHTS RESERVED

おしまい

ありがとうございました