-
Notifications
You must be signed in to change notification settings - Fork 3
学習の要点
- プロジェクトの構造
- trait
- sealed 修飾子
- case class
- type
- package object
- Scalaにおけるアクセス修飾子
- Scalaコレクションの概要
Function1
の省略形
以下、怖くない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"
}
- Javaでいうインターフェースみたいなもの
- フィールドも持てるし、メソッドの実装も持てる
- 継承を同一ファイル内に限定する修飾子
root/src/main/scala/pkg/name/Foo.scala
sealed trait Foo {
val bar: String
}
case class Baz(bar: String) extends Foo
- コンストラクターとか、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
を使うことで型の別名を使うことができる
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
というものを作って、パッケージ内で共通に使える
関数、型、値などを定義できる。
root/src/main/scala/pkg/name/package.scala
package object hoge {
type UserId = Int
}
- 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"
}
Traversable - foreachのみ定義されたtrait
└ Iterable - iteratorのみ定義されたtrait
├ Seq - 順番を持つ集合(重複あり)
│ ├ IndexedSeq - ランダムアクセスに特化
│ └ LinearSeq - 順列アクセスに特化
├ Set - 集合(重複なし)
└ Map - 辞書
よくあるやつ
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)