Closing a resource stored in Option[ ]
I have a resource object stored in an option.
private var ochan: Option[Channel] = None
At some point during program execution, ochan
is set to Some(channel)
. I'd like to close the channel (via invoking the method close
) and set the option to None
in one fatal swoo开发者_开发技巧p.
Currently I have:
def disconnect = ochan = { ochan.foreach{_.close}; None }
And previously I had:
def disconnect = ochan = ochan.flatMap{ o => o.close; None }
Is there a better way to do this?
I'd write it like this:
def disconnect = ochan = ochan match {
case Some(ch) => ch.close(); None
case None => None // do nothing
}
instead of using foreach
or flatMap
. In my opinion, this solution shows more clearly and explicitly what happens. The solution with foreach
or flatMap
requires an extra mental jump, you'd have to know what these methods do on an Option
.
I don't know that it's better but it's shorter (once you've defined the implicit):
implicit def closer(o: Option[Channel]) = new {
def close(): Option[Channel] = { o.foreach(_.close); None }
}
def disconnect = ochan = ochan.close
There is no big difference between an immutable var and a mutable val. So why not encapsulate the behavior in a separate class, when you want to have mutability anyway?
class ChannelOption {
private var _channel :Option[Channel] = None
def channel = _channel
def channel_=(ch:Option[Channel]) { _channel.foreach(_.close); _channel = ch }
}
Usage:
private val ochan = new ChannelOption
ochan.channel = Some(getAChannel)
ochan.channel.foreach(useChannel)
ochan.channel = Some(getAnotherChannel) //this automatically closes the first channel
ochan.channel = None //this automatically closes the second channel
It's not thread safe! Remember to use @volatile (not here; using synchronization), and do something like this: (this is why I don't like imperative code)
private val lock = new Object
def disconnect() {//Function has side effects: remember parenthesis!
lock.synchronized { //Synchronizations is important; you don't want to close it multiple times
ochan.foreach {_.close()} //Again: side effects -> parens.
}
}
And if you don't use parallel programming, you are doing something wrong.
You could define ochan_=
so that assigning a new value to ochan
closes the old channel (similar to std::auto_ptr<>
in C++) but I don't see how you can encapsulate that in a child class of Option[Channel]
because the storage is in your class. The solution wouldn't change the code much at all, it would just make disconnect
implicit by assigning ochan
.
I guess this could work:
def disconnect {
ochan = {
ochan.get.close
None
}
}
or
def disconnect {
ochan.get.close
ochan = None
}
Anyway since there is mutating operation, it will always need 2 calls (1 for close and one for assignment of None).
精彩评论