Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
JavaエンジニアのためのScala入門 #jjug_ccc #ccc_l2

JavaエンジニアのためのScala入門

2017/05/20 JJUG CCC 2017 Spring JJUG CCC 2017 Spring http://www.java-users.jp/ccc2017spring/

自己紹介

  • Abe Asami “きの子”
  • 大阪のフリーランスプログラマ
  • http://nocono.net/
  • @aa7th
  • Scala、Andorid(Kotlin)
    • 祝・KotlinAndroid公式化
  • Scala関西、関西Java女子部 主催

Scala関西Summit2017開催します!

  • 関西最大のScalaカンファレンス
    • 去年の参加者は関係者込みで約180人
  • 9/9(土) 天満研修センター
    • 大阪駅の隣の駅
  • summit.scala-kansai.org

本日の内容

今日話すこと

  • Scalaのはじめかた
  • 基本文法のほんの1部を紹介
  • 私的に便利だなーと感じている機能
    • String Interpolation
    • 中置記法
    • case class
    • パターンマッチ
  • Scalaを始めた頃戸惑った文法
    • 括弧記法ルール
    • implicits paramater
  • ここが好きだよScala

今日あまり話さないこと

  • Javaをやっている方なら理解に困らないであろう機能
    • クラス
    • 基本制御構文
    • trait (JavaでいうところのInterface)
    • ラムダ式
    • Option (Optional)

などはあまり 説明しません。

Scalaとは

  • オブジェクト指向と関数型言語両方の特性を併せ持つJVM言語
    • コンパイルをするとJavaのバイトコードが生成される
    • Javaのライブラリを利用することが可能

関数型言語

  • 関数を第1級オブジェクトとして扱う
    • メソッドの引数に関数を渡すことができる
  • 副作用がないプログラムを目指す
    • Scalaは副作用を許容する非純粋関数型言語。
    • 副作用を「なるべく」なくす・局所化して処理を書くことが推奨されている。
    • 変数への代入を避けて定数を使用する
    • 同一の入力値に対して、必ず同一の結果が返ってくる関数を組み合わせ、プログラムを組んでいく
      • 保守性が高い
      • 並列処理に強い

はじめかた

必要なもの

  • JDK
  • SBT (ScalaBuildTool)
    • Scala標準のビルドツール
    • Activatorという公式のカスタム版SBTがあったが、最近EOLになった

開発環境

  • IntelliJ IDEA
    • 単にScalaを書くだけであれば無償版で使える。有償版だとPlayFrameworkサポートなどが使える。
  • Vim・Emacsなどのテキストエディタ

学び方

  • Scalaスケーラブルプログラミング第3版
  • Scala逆引きレシピ
    • 内容が少し古い可能性があるので注意

Web教材

レビューサービス

  • Tech to Value (がくぞ) さん
  • 他にもScala導入時に有名なエンジニアさんにアドバイザーとしてはいってもらう例はよく聞きます

サンプルコード

// 変数

// 型推論・セミコロン不要
var str1 = "再代入可能な変数です"
val str2 = "再代入不可能な定数です"

// varは極力避けて、valを利用するのが一般的

/**
  * プロパティ from と to を持つクラス
  */
class Hello(val from: String, val to: String) {

  /**
    * 挨拶を出力するメソッド
    */
  def sayHello(): Unit = {
    // printlnはインポートしなくても利用できる
    // String Interpolation機能により、文字列中に変数を埋め込むことが可能
    println(s"$from: こんにちは, $to さん!")
  }

  // 処理が1行である場合、波括弧は省略できる 
  // (※ 2017/05/23 追記:「省略できる」という表現は語弊があるとのことです。 https://twitter.com/kmizu/status/865250818345193472)
  // 引数がないメソッドは()を省略可能 ※一般的に副作用が生じるメソッドは()を省略するべきではないので、これは本当はよくない例です。
  // 型推論により戻り値の型を省略可能 (書く方が無難)
  def sayHello2 =
    println(s"$from: こんにちは, $to さん!")

}

val hello = new Hello("きの子", "うらがみ")
hello.sayHello()
hello.sayHello2


/**
  * objectキーワードでシングルトンオブジェクトとなる
  * (JavaでいうところのStaticは存在しない)
  */
object Sample {
  private val pi = 3.14

  // 円の面積
  def areaOfCircle(radius: Int): Double = {
    // ifは「文」ではなく「式」なので結果を返す
    val result =
      if(radius > 0)
        radius * radius * pi
      else
        0

    // returnキーワードはいらない
    result
  }
}

// シングルトンなのでnewしなくても使える
Sample.areaOfCircle(3)
Sample.areaOfCircle(-3)

// 実は演算子もメソッド
// 「+」はIntのメソッド名
1 + 2 + 3    // 中置記法によりこのように書くことができる
// 1.+(2.+(3)) ← 間違い
(1.+(2)).+(3)  // 2017/05/23 Twitterでご指摘頂いた点訂正: https://twitter.com/xuwei_k/status/865828669087928320

// 自分で演算子を作ることも可能。 (最後、時間があればご紹介します)

// 両方1から5のリスト
List(1, 2, 3, 4, 5)
// toはRange型を返却するIntのメソッド
(1 to 5).toList

// 1から5のリストに1を足しながら出力
for(num <- (1 to 5)) {
  println(num + 1)
}

// map関数を利用した例
// => は関数リテラル
val list = (1 to 5).toList
list
  .map(num => num + 1)
  .foreach(println(_)) // foreach(num => println(num)) と同義

// 処理がブロック(複数行)になる場合、波括弧でくくる
list.map { num =>
  val tmp = num + 1
  tmp * 3
}

case class

/**
  * case class
  *
  * getter, setterやtoStringやequalsが自動生成される
  * POJOクラスを作成するのに便利
  */
case class Person(name: String, age: Int)


// case classはnewキーワードが不要
val kinoko = Person("きの子", 18)
val kinoko2 = Person("きの子", 18)

if(kinoko == kinoko2) "同一人物です" else "別人"

// toStringできちんと中の値が分かる形で文字列化してくれる
println(kinoko.toString)

パターンマッチ

//
// パターンマッチ
//

// 
// パターンマッチはmatch式などで使うことができる。
// match式はJavaのSwitch文の強い版みたいなやつ
// 

"s" match {
  case "s" => "OK"
  case _ => "NG"
}

// 型でマッチさせることも可能
// (コップ本より引用)
def generalSize(x: Any) = x match {
  case s: String => s.length
  case m: Map[_, _] => m.size
  case _ => -1
}

generalSize("abc")
generalSize(Map(1 -> 'a', 2 -> 'b'))
generalSize(5)


// case classやOption、タプルなどを分解して
// 中身を抽出することができる
case class Person(name: String, age: Int)

def introduction(x: Any) = x match {
  case Person(name, age) => s"$name $age さい"
  case _ => "知らない子です"
}

val kinoko = Person("きの子", 18)
introduction(kinoko)
introduction("たけのこ")

Implicit Parameter (暗黙のパラメータ)

def create(
  userName: UserName)(implicit s: DBSession): UserId = {
  // このメソッドのシグネチャは
  // def createWithAttributes(parameters: (Symbol, Any)*)(implicit s: DBSession): Id
  // DBSessionは明示的に渡していないが、implicitなので暗黙的に渡されている
  createWithAttributes('userName -> userName.value)
}
  • PlayFrameworkやO/Rマッパーなどで、このように共通で引き回すことになるオブジェクト(Reqest, Configuration, Connection...etc)を暗黙的に渡す用途をよく目にする
  • Implicitは他にも色々な機能を提供してくれるものであり、このような引数ひきまわしのための機能というわけではないので、そこは注意。
  • ただ、おそらく初心者が最初に目にする用途はこれだと思うので、今日はご紹介しました。

個人的にScalaの好きなところ

  • シンプルな文法
    • よく「Scalaは難しい」と言われるが、最低限覚えるべき文法自体はさほど多くなく、シンプルだと思う。
  • すっきりしたコードが書ける
  • 表現力が豊か
case class Point(x: Int, y: Int) {
  def add(p: Point) =
    Point(this.x - p.x, this.y - p.y)

  def +(p: Point) = add(p)
}

// 3行とも、Pointの和を取る処理
// res0: Point = Point(280,-200)
Point(300, 100).add(Point(20, 300))
Point(300, 100) add Point(20, 300)
Point(300, 100) + Point(20, 300)
  • 最初、すんなりコードを読むことができたかといわれると正直そんなことはなかった
    • ただ、ルールさえ覚えてしまえば、むしろ読みやすく感じる
  • 「Scalaは書いていて気持ちいい!楽しい!!」という声はよく聞くし、私もそう感じる。

まとめ

Scalaたーのしー! ₍₍⁽⁽(ી(´・ᴗ・`)ʃ)₎₎⁾⁾

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment