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
}
}