Last active
December 17, 2015 14:49
-
-
Save ryoco/5626998 to your computer and use it in GitHub Desktop.
rpscala 104回で質問させていただいた スライド
題名と質問したい事がズレているがそのまま
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* rpscala 104回 で tototoshi さんが書いてくださった sample code の記憶を頼りにして書いたもの。 | |
* unapply は Boolean でもり値にできるよというのと、 | |
* paramTOStatus のようなものを書きたいのであれば list に object 書けば、という話 | |
* (であってます。。。?) | |
*/ | |
sealed abstract class Status(val id: Int) { | |
def unapply(i: Int): Boolean = i == id | |
} | |
case object OK extends Status(1) | |
case object Error extends Status(2) | |
case object Unknown extends Status(99) | |
object Status { | |
val statuses = List(OK, Error) | |
def paramToStatus(param: Int): Status = { | |
statuses.find(_.id == param).getOrEles(Unknown) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!SLIDE | |
Scala で Enum 的な | |
============== | |
* 参考にしたページ | |
* http://xerial.org/scala-cookbook/recipes/2012/06/29/enumeration/ | |
!SLIDE | |
なにがしたい? | |
-------------- | |
* Web appli なので、parameter を数値などで引き継ぐ事が多いため、Intで場合分けが多い | |
* そうでなくとも DB の値とか | |
```scala | |
def paramToResult(param: Int): String = { | |
param match { | |
case 1 => { | |
... // 何か処理 | |
"OK!" | |
} | |
case 2 => { | |
... // 何か処理 | |
"ERROR!" | |
} | |
}} | |
``` | |
マジックナンバーは使いたくありませんし | |
!SLIDE | |
Enumを使う | |
-------------- | |
```scala | |
object Status extends Enumeration { | |
val OK = Value(1) | |
val Error = Value(2) | |
} | |
def paramToStatus(param: Int): Status.Value = { | |
param match { | |
case Status.OK.id => Status.OK | |
case Status.Error.id => Status.Error | |
} | |
} | |
``` | |
* Status.Value が気持ちわるいし、Value を書くのを忘れる | |
!SLIDE | |
case object を使う | |
-------------- | |
```scala | |
sealed abstract class Status(val id: Int) | |
object Status { | |
case object OK extends Status(1) | |
case object Error extends Status(2) | |
} | |
def paramToStatus(param: Int): Status = { | |
param match { | |
case Status.OK.id => Status.OK | |
case Status.Error.id => Status.Error | |
} | |
} | |
``` | |
* 冗長な気がするが、Status.Value はなくなった。 | |
!SLIDE | |
case object を更に拡張する | |
-------------- | |
* Enum はたぶん、Valueの拡張もできないしあんまり使い勝手がよくないので case object を使う体で | |
```scala | |
sealed abstract class Status(val id: Int) { | |
def bonus: Double | |
} | |
``` | |
case object を返す時に bonus の値を決めたいのだがどうすればよいのか | |
```scala | |
object Status { | |
case object OK extends Status(1) // bonus がないのでエラー | |
case object Error extends Status(2) // bonus がないのでエラー | |
} | |
def paramToStatus(param: Int): Status = { | |
val calcBonusPoint: Double = { ... } | |
param match { | |
case Status.OK.id => { | |
val bonus = calcBonusPoint | |
Status.OK // bonus もいっしょに返したい | |
} | |
case Status.Error.id => { | |
val bonus = calcBonusPoint | |
Status.Error // bonus もいっしょに返したい | |
} | |
} | |
} | |
``` | |
!SLIDE | |
方法 | |
-------------- | |
* var を使って、getter, setter を定義 | |
* var か… | |
* case class を作成して、 case object がそれを継承する | |
* けっこう冗長になる | |
* ラップする | |
* スライド書いてて思いついたけどこれがいちばんマシかも? | |
!SLIDE | |
var | |
-------------- | |
```scala | |
sealed abstract class Status(val id: Int) { | |
var bonus: Double = 0.0 | |
def bonus_(_bonus: Double) { | |
bonus = _bonus | |
} | |
} | |
object Status { | |
case object OK extends Status(1) | |
case object Error extends Status(2) | |
} | |
def paramToStatus(param: Int): Status = { | |
param match { | |
case Status.OK.id => { | |
val result = Status.OK | |
result.bonus = 0.11 | |
result | |
} | |
case Status.Error.id => { | |
val result = Status.Error | |
result.bonus = 1.23 | |
result | |
} | |
} | |
} | |
``` | |
(動くか自信ないです) | |
!SLIDE | |
case class | |
-------------- | |
```scala | |
sealed abstract class Status(val id: Int) { | |
def bonus: Double | |
} | |
case class OK(val bonus: Double) extends Status(1) | |
case class Error(val bonus: Double) extends Status(2) | |
object Status { | |
case object OK extends OK(0.0) | |
case object Error extends Error(0.0) | |
} | |
def paramToStatus(param: Int): Status = { | |
param match { | |
case Status.OK.id => { | |
new OK(0.11) | |
} | |
case Status.Error.id => { | |
new Status(1.23) | |
} | |
} | |
} | |
``` | |
キモい | |
!SLIDE | |
ラッパー | |
-------------- | |
```scala | |
sealed abstract class Status(val id: Int) | |
object Status { | |
case object OK extends Status(1) | |
case object Error extends Status(2) | |
} | |
class StatusWrap(s: Status, bonus: Double) | |
def paramToStatusWrap(param: Int): StatusWrap = { | |
param match { | |
case Status.OK.id => { | |
new StatusWrap(Status.OK, 0.11) | |
} | |
case Status.Error.id => { | |
new StatusWrap(Status.Error, 1.23) | |
} | |
} | |
} | |
``` | |
Tuple でかけと言われた。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
結論として unapply 使えば match とかかかなくて済むよね、という話と、bonus のようになんか計算して値を返したい場合はタプルにするなどして Status とは別ものとして扱うべき、というご指摘をいただきました。
takezoux2 さんが gist 書いてくださいました。
https://gist.github.com/takezoux2/5627080