Scala - Реализация кругового робина без изменяемых типов

В настоящее время я пытаюсь найти свой путь в мир Скала. На самом деле я пытаюсь реализовать стратегию Round Robin без изменяемых типов.

У меня есть объект Scala с начальным списком хостов и метод для получения следующего хоста.

Object RoundRobin { 
  val optHosts: Option[List[String]] = Option[List[String]]("host1", "host2") // get from Configfile later
  var hosts: List[String] = optHosts.getOrElse(List())

  def url: String = {
    hosts = hosts.tail ++ List(hosts.head)
    hosts(0)
  }

  def execute = ??? // do something with the next host

}

Я читал об неизменяемых очередях в Scala, но я не знаю, как решить эту проблему с неизменяемыми типами. Каким-то образом я должен был бы помнить индекс правильно? Это один из случаев, когда нет смысла использовать неизменяемые типы?

2 ответа

Решение

Если я правильно понимаю, каждый раз, когда вы вызываете execute для объекта, он будет использовать другой элемент. Затем, потому что объект должен инкапсулировать состояние, поэтому нет никакого способа обойти var

var hosts = collection.immutable.Queue ++ optHosts.getOrElse(List())
def url: String = {
   val(element,queue) = hosts.pop
   hosts = queue.enqueue(element)
   element
}

По поводу ваших вопросов...

Каким-то образом я должен был бы помнить индекс правильно?

Да, смотри выше. Но также нет, см. Ниже.

Это один из случаев, когда нет смысла использовать неизменяемые типы?

Зависит. Если вы хотите сохранить свой object RoundRobin тогда ясно, что этот объект является изменяемым, и вы, таким образом, имеете выбор только между изменяемыми значениями и неизменяемыми значениями. (ну, вы могли бы также иметь переменные, которые указывают на изменяемые структуры, но зачем вам это делать?)

С другой стороны, вы также можете выбрать совершенно другой подход:

class RoundRobin private(left: List[String], all: List[String]) {
   def this(all :List[String]) = this(all, all)
   assume(all.nonEmpty)
   val theElement = left.headOption.getOrElse(all.head)
   def nextRoundRobin = new RoundRobin(if(left.nonEmpty) left.tail else all, all) 
   def execute = {
       // do something with theElement
       println(theElement)
       // return an object that will execute on the next element
       nextRoundRobin
   }
 }

 new RoundRobin(List("1","2")).execute.execute.execute
 // prints 1 2 1

Когда вы используете эту версию RoundRobin, каждый раз, когда вы вызываете execute, вы получите объект циклического перебора, который будет использовать следующий элемент в режиме циклического перебора. Очевидно, что объект, использующий RoundRobin, снова может быть изменяемым или неизменным.

Сделано небольшое изменение, так что теперь класс будет циклически повторяться при выполнении более трех раз, как в приведенном примере.

 class RoundRobin private(left: List[String], all: List[String]) {
      def this(all :List[String]) = this(all, all)
      assume(all.nonEmpty)
      val theElement = left.headOption.getOrElse(all.head)
      def nextRoundRobin = new RoundRobin(if(left.nonEmpty) left.tail else all.tail, all)
      def execute = {
        // do something with theElement
        println(theElement)
        // return an object that will execute on the next element
        nextRoundRobin
      }
    }
Другие вопросы по тегам