Skip to content
mike-neck edited this page Oct 1, 2014 · 2 revisions

学習の要点

以下、怖くないScala勉強会(仮題)のハンズオンでやることのポイント

プロジェクトの構造

ディレクトリーの構造

Javaのプロジェクトと同じ構造

root
  └ src
    ├ main
    │ └ scala
    │   └ pkg
    │     └ name
    └ test
      └ scala
        └ pkg
          └ name
パッケージ名

Javaと同じでもいいし、ディレクトリーの構造に合わせてなくてもよい

Javaと同じでパッケージとディレクトリーをあわせる場合

root/src/main/scala/pkg/name/Hoge.scala

package pkg.name
object Hoge {
  val foo: String = "bar"
}

パッケージとディレクトリーをあわせない場合

root/src/main/scala/pkg/name/Hoge.scala

package hoge
object Hoge {
  val foo: String = "bar"
}

trait

  • Javaでいうインターフェースみたいなもの
  • フィールドも持てるし、メソッドの実装も持てる

sealed 修飾子

  • 継承を同一ファイル内に限定する修飾子

root/src/main/scala/pkg/name/Foo.scala

sealed trait Foo {
  val bar: String
}
case class Baz(bar: String) extends Foo

case class

  • コンストラクターとか、toStringとか、equalsとかhashCodeまで自動で作ってくれる便利なやつ

root/src/main/scala/pkg/name/User.scala

trait User {
  val name: String
  val address: String
}
case class PersonalUser(name: String, address: String, age: Int) extends User
case class CompanyUser(name: String, address: String, cio: String) extends User

case classを使うと次のようなクラスが自動で生成される

class PersonalUser(val name: String, val address:String, val age: Int) extends User {
  def toString: String = {
    s"PersonalUser($name,$address,$age)"
  }
  def equals(other: Any): Boolean = ???
  def hashCode: Int = ???
}
object PersonalUser extends AbstractFunction3[String, String, Int, PersonalUser] with User {
  val age: Int
  override def apply(name: String, address: String, age: Int): PersonalUser = {
    new PersonalUser(name, address, age)
  }
  def unapply(p: PersonalUser): Option[(Sting, String, Int)] = {
    Some((p.name, p.address, p.age))
  }
}

case classでクラスを作った場合は、パターンマッチがものすごい便利になる

def hoge(user: User): String = {
  user match {
    case User(name, "東京") => s"$name(東京の人)"
    case User(name, "町田") => s"$name(神奈川の人)"
    case _ => "どうでもいい"
  }
}
  • case classを使わない場合は次のような感じでフィールドのところにvalをつける
class PersonalUser(val name: String, val address: String, val age: Int) extends User

type

  • typeを使うことで型の別名を使うことができる

root/src/main/scala/pkg/name/package.scala

package object hoge {
  type UserId = Int
}

別名をつけると、型名がわかりやすい意味を持ってくる

root/src/main/scala/pkg/name/UserRepo.scala

object UserRepo {
  private var userCache: Map[UserId, User] = Map()
}

UserIdからUserを取り出せるという風に読みやすくなる

package object

package objectというものを作って、パッケージ内で共通に使える

関数、型、値などを定義できる。

root/src/main/scala/pkg/name/package.scala

package object hoge {
  type UserId = Int
}

Scalaにおけるアクセス修飾子

  • Javaに比べて結構柔軟なアクセス修飾子

root/src/main/scala/pkg/name/Hoge.scala

package hoge
object Hoge {
  //ゲッターが見える
  val foo = "foo"
  //このクラスでゲッターが見える
  private val bar = "bar"
  //継承したクラスでゲッターが見える
  protected val baz = "baz"
  //パッケージだけでゲッターが見える
  private[hoge] val ban = "ban"
  //このオブジェクト限定でゲッターが見える
  private[this] val bam = "bam"
}

Scalaコレクションの概要

Scalaコレクションの概要

Scalaコレクションの概要

Traversable - foreachのみ定義されたtrait
 └ Iterable - iteratorのみ定義されたtrait
   ├ Seq - 順番を持つ集合(重複あり)
   │  ├ IndexedSeq - ランダムアクセスに特化
   │  └ LinearSeq - 順列アクセスに特化
   ├ Set - 集合(重複なし)
   └ Map - 辞書

Function1の省略形

よくあるやつ

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy(new Function1[User, UserId] {
  def apply(u: User): UserId = u.id
})

Function=>を使って省略できる

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy(new ((User) => UserId) {
  def apply(u: User): UserId = u.id
})

def apply=>を使って記述できる

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy((u:User) => u.id)

引数の型が自明のときは、型アノテーションを省略できる

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy((u) => u.id)

引数がひとつ(Function1)の場合、引数グループの括弧を省略できる

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy(u => u.id)

引数が1回のみ使われる場合は、引数の宣言を省略して_で記述できる

val users: Map[UserId, User] = ...
users.values.toSeq.sortBy(_.id)