我有一个存储在选项中的资源对象。
private var ochan: Option[Channel] = None
在程序执行期间的某个时刻,ochan
设置为Some(channel)
。我想关闭频道(通过调用方法close
)并将选项设置为None
一次致命一击。
目前我有:
def disconnect = ochan = { ochan.foreach{_.close}; None }
以前我曾经:
def disconnect = ochan = ochan.flatMap{ o => o.close; None }
有更好的方法吗?
答案 0 :(得分:5)
我会这样写:
def disconnect = ochan = ochan match {
case Some(ch) => ch.close(); None
case None => None // do nothing
}
而不是使用foreach
或flatMap
。在我看来,这个解决方案更明确,更明确地显示了会发生什么。使用foreach
或flatMap
的解决方案需要额外的精神跳跃,您必须知道这些方法对Option
执行的操作。
答案 1 :(得分:3)
我不知道它更好但是它更短(一旦你定义了隐含的):
implicit def closer(o: Option[Channel]) = new {
def close(): Option[Channel] = { o.foreach(_.close); None }
}
def disconnect = ochan = ochan.close
答案 2 :(得分:1)
不可变var和可变val之间没有太大区别。那么,为什么不将这种行为封装在一个单独的类中,当你想要具有可变性时呢?
class ChannelOption {
private var _channel :Option[Channel] = None
def channel = _channel
def channel_=(ch:Option[Channel]) { _channel.foreach(_.close); _channel = ch }
}
用法:
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
答案 3 :(得分:1)
这不是线程安全的!记得使用@volatile(不在这里;使用同步),并做这样的事情:(这就是为什么我不喜欢命令式代码)
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.
}
}
如果你不使用并行编程,那你就做错了。
答案 4 :(得分:0)
您可以定义ochan_=
,以便为ochan
分配新值会关闭旧频道(类似于C ++中的std::auto_ptr<>
),但我不知道如何将其封装在由于存储在您的班级中,因此Option[Channel]
的子类。该解决方案根本不会更改代码,只会通过分配disconnect
来隐式ochan
。
答案 5 :(得分:0)
我想这可行:
def disconnect {
ochan = {
ochan.get.close
None
}
}
或
def disconnect {
ochan.get.close
ochan = None
}
无论如何,由于存在变异操作,它总是需要2个调用(1个用于关闭,1个用于分配无)。