I'm rater new to scala, but basically have found my way around...
Here, I'm asking for the recommended/best practice/idiomatic way of implementing this:
- internally, MyClass uses a state type, which is implemented by a sealed hierarchy of case classes
- but on the API, only some boolean predicate should be exposed, which gets implemented by matching against the (in开发者_开发技巧ternal) state.
Currently, my implementation is along the lines of...
def isSane: Boolean = state match {
case Ok(_,'valid) => true
case _ => false
}
But this solution feels awkward to me, as if expressing something in 3 lines of code which has only information content worth one line of code. Actually, what I'd like to write would be:
def isSane: boolean = state matches Ok(_, 'valid)
Probably/likely it's possible to implement a suitable operator yourself in scala, but before I look into that, I'd like to know what would be the usual way to solve this problem. Maybe there's also some existing library implementation around?
I'd do something like this:
abstract class State {
def matches(pf: PartialFunction[State, Unit]) = pf isDefinedAt this
}
// then
def isSane = state matches { case Ok(_,'valid) => }
Because matches
is defined to receive a partial function, you can follow it with a function literal with only the case statements that should result in true. You do not need to return anything, as the partial function is defined as returning Unit
. Finally, the matches
method uses the isDefinedAt
method of partial functions to verify if there's a case statement covering itself.
I may be old-fashioned, but why not use polymorphism?
trait State { def sane: Boolean }
trait InvalidState extends State { def sane = false }
case class Ok(whatever: Whatever, s: Symbol) extends State {
def sane = { s == 'valid }
}
case class Failure(msg: String) extends InvalidState
case class WarmingUp extends InvalidState
// ...
def isSane(): Boolean = state.sane
Of course, if that's not a possibility for whatever reason, you can generalize Daniel's solution somewhat:
class Matcher[T](o: T) {
def matches(pf: PartialFunction[T, Unit]) = pf isDefinedAt o
}
object Matcher {
implicit def o2matcher[T](o: T): Matcher[T] = new Matcher(o)
}
// then
def isSane = state matches { case Ok(_,'valid) => }
If the Symbol
property is statically known to be a property of the type of state
:
def isSane: Boolean =
state.secondSymbolPropertyWhateverItsCalled == 'valid
If you don't know that state
is an Ok
, then:
def isSane: Boolean =
state.isInstanceOf[Ok] && state.asInstanceOf[Ok].symbolProp == 'valid
but at this point, it's not really superior to what you wrote.
Lastly, you could just define isSane
on that hierarchy of types and delegate to it:
def isSane: Boolean =
state.isSane
精彩评论