Закрытие ресурса, хранящегося в Option [] - PullRequest
2 голосов
/ 07 апреля 2011

У меня есть объект ресурса, сохраненный в опции.

 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 }

Есть ли лучший способ сделать это?

Ответы [ 6 ]

5 голосов
/ 08 апреля 2011

Я бы написал так:

def disconnect = ochan = ochan match {
  case Some(ch) => ch.close(); None
  case None => None // do nothing
}

вместо использования foreach или flatMap. На мой взгляд, это решение более четко и ясно показывает, что происходит. Решение с foreach или flatMap требует дополнительного умственного прыжка, вам нужно знать, что эти методы делают на Option.

3 голосов
/ 08 апреля 2011

Я не знаю, что это лучше, но оно короче (как только вы определили неявное):

implicit def closer(o: Option[Channel]) = new { 
  def close(): Option[Channel] = { o.foreach(_.close); None } 
}

def disconnect = ochan = ochan.close
1 голос
/ 08 апреля 2011

Это не потокобезопасно! Не забудьте использовать @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.
  }
}

А если вы не используете параллельное программирование, вы делаете что-то не так.

1 голос
/ 08 апреля 2011

Нет большой разницы между неизменяемым 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
0 голосов
/ 08 апреля 2011

Полагаю, это может сработать:

def disconnect { 
  ochan = {
    ochan.get.close
    None
  }
}

или

def disconnect {
  ochan.get.close
  ochan = None
}

В любом случае, так как существует операция мутирования, ей всегда потребуется 2 вызова (1 для закрытия и один для назначениянет).

0 голосов
/ 08 апреля 2011

Вы можете определить ochan_=, чтобы присвоение нового значения ochan закрывало старый канал (аналогично std::auto_ptr<> в C ++), но я не понимаю, как вы можете инкапсулировать это в дочерний класс Option[Channel] потому что хранилище находится в вашем классе.Решение не сильно изменило бы код, оно просто сделало бы disconnect неявным путем присвоения ochan.

...