Scalaでも値が範囲に入っているか確認したい
はじめにとおわりに
Scalaで整数が特定の範囲に入っているかを宣言的に書けないかなと思ったのですが、やっぱり書けました。
val range = 0 to 255 println(range contains -1) println(range contains 0) println(range contains 20) println(range contains 255) println(range contains 256) val range2 = 0 until 255 println(range2 contains 254) println(range2 contains 255)
false true true true false true false
これだけです。
おわり
Akkaのエラーハンドリングストラテジを確認したい
はじめに
Akkaを実運用に突っ込もうと考えたときに一番最初に気になるのはActorがくたばった時の挙動ですよね。 知らない間にActorがくたばっていてメッセージだけが虚空の彼方に消えていったなんて事態になった日には次回の自身のボーナスも虚空に消えかねません。
ボーナスを死守するためにもエラーハンドリングは必須の知識として学ぶべきです。
サンプルコード
今回はこんな感じのサンプルコードを使用します。
package org.jyuch import akka.actor.SupervisorStrategy.{Escalate, Restart, Resume, Stop} import akka.actor.{Actor, ActorSystem, OneForOneStrategy, Props} import scala.concurrent.duration._ import scala.language.postfixOps object Hello { def main(args: Array[String]): Unit = { val system = ActorSystem() val calc = system.actorOf(CalcActor.props()) calc ! Add(1, 2) calc ! Add(-1, 2) calc ! Add(1, 2) calc ! Subtract(3, 2) io.StdIn.readLine() system.terminate() } } trait OperandActor extends Actor { override def postRestart(reason: Throwable): Unit = { super.postRestart(reason) //println(reason.getClass.getTypeName) } } class CalcActor extends OperandActor { val add = context.actorOf(AddActor.props(), "add") val subtract = context.actorOf(SubtractActor.props(), "subtract") def receive = { case Result(v) =>{ println(this + " : " + v) } case a: Add => add ! a case s: Subtract => subtract ! s } override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: Exception => Stop } } object CalcActor { def props(): Props = Props[CalcActor] } class AddActor extends OperandActor { def receive = { case Add(x, y) => { println(this) if (x < 0 || y < 0) throw new Exception() sender() ! Result(x + y) } } } object AddActor { def props() = Props[AddActor] } class SubtractActor extends OperandActor { def receive = { case Subtract(x, y) => { println(this) if (x - y < 0) throw new Exception() sender() ! Result(x - y) } } } object SubtractActor { def props() = Props[SubtractActor] } sealed abstract class Operand case class Add(x: Int, y: Int) extends Operand case class Subtract(x: Int, y: Int) extends Operand case class Result(value: Int)
子Actorの後始末
エラーハンドリングストラテジは親ActorのsupervisorStrategy
で制御されますが、何も指定しない(デフォルト)とくたばったActorだけを再起動します。
supervisorStrategy
で指定できるストラテジは以下の感じになります。
ストラテジ | 意味 |
---|---|
OneForOneStrategy |
子Actorがくたばったらそいつだけ何とかする |
AllForOneStrategy |
子Actorがくたばったらすべての子Actorを何とかする |
で、何とかする内容が以下の感じです。
ストラテジ | 意味 |
---|---|
Escalate |
上位のActorに判断を委譲する |
Restart |
子Actorを再起動する |
Resume |
エラーを気にせず続行する |
Stop |
子Actorを停止する |
そして、ストラテジをこんな感じに指定します。
import akka.actor.OneForOneStrategy import akka.actor.SupervisorStrategy._ import scala.concurrent.duration._ override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException ⇒ Resume case _: NullPointerException ⇒ Restart case _: IllegalArgumentException ⇒ Stop case _: Exception ⇒ Escalate }
ガーディアンアクター
上記の指定で子がくたばった時の挙動を制御できるようになりました。じゃあ自身がくたばったらどうなるのさ?
自身がほかのActorの子だったらそいつが決めますが、自身がsystem.actorOf
が生成されていた場合は自身の命運はガーディアンアクターが決めます。
Akka 2.1以降では設定ファイルのakka.actor.guardian-supervisor-strategy
でガーディアンアクターのストラテジを設定出来ます。
actor { # Either one of "local", "remote" or "cluster" or the # FQCN of the ActorRefProvider to be used; the below is the built-in default, # note that "remote" and "cluster" requires the akka-remote and akka-cluster # artifacts to be on the classpath. provider = "local" # The guardian "/user" will use this class to obtain its supervisorStrategy. # It needs to be a subclass of akka.actor.SupervisorStrategyConfigurator. # In addition to the default there is akka.actor.StoppingSupervisorStrategy. guardian-supervisor-strategy = "akka.actor.DefaultSupervisorStrategy"
現状ではakka.actor.StoppingSupervisorStrategy
かakka.actor.DefaultSupervisorStrategy
が指定できるようです。
おわりに
これならActorがくたばったときにいい感じにActorを再起動できそうです。
これでボーナスを心配することなく安心して今夜も眠ることが出来そうです。
おわり
Scalaでも演算子のオーバーロードをしたい
はじめに
Scalaの演算子オーバーロードについてサクッと確認してみます。
オーバーロード
まぁ、とりあえず言語仕様を見ておけば安心だよねといった感じです。困ったら公式ドキュメントを読む。日本書紀にもそう書いてあります。
case class AltInt(val value: Int) { def +(x: AltInt) = plus(x) def plus(x: AltInt) = AltInt(value + x.value) def unary_~ = AltInt(value * -1) def +:(x: Int) = AltInt(value + x) def -:(x: AltInt) = { println(s"$value - ${x.value} = ${value - x.value}"); AltInt(value - x.value) } def *(x: AltInt) = AltInt(x.value * value) def ! = println(value) }
中置演算子
Scalaでは引数を一つ取るメソッドはすべて中置演算子として扱えます。
逆に+
のような演算子も普通*1のメソッドのように呼び出せます。
val a = AltInt(10) val b = AltInt(20) println(a.plus(b)) println(a plus b) println(a.+(b)) println(a + b)
なお、優先順位はメソッドの先頭の文字によって規定されるようです。
先頭の文字 | 優先度 |
---|---|
(all letters) | 低い |
| | |
^ | |
& | |
= ! | |
< > | |
: | |
+ - | |
* / % | |
(all other special characters) | 高い |
val a = AltInt(10) val b = AltInt(20) println(a * a + b) // 120
また、メソッドが:
で終わる場合は引数とレシーバの位置関係が逆転します。
println(1 +: a)
また、通常演算子は左結合ですがこの場合は右結合になります。
println(b -: a -: a)
10 - 10 = 0 0 - 20 = -20 AltInt(-20)
後置演算子
中置演算子と同じように引数を取らないメソッドは後置演算子として呼び出せます。
println(a!) println(a.!)
前置演算子
前置演算子はunary_記号
で定義できますが、記号に入ることができるのは+
・-
・!
・~
に限られます。
println(~a) println(a.unary_~)
おわりに
素直でいいですね。
*1:普通?普通ってなんだ?