Scala - 在没有可变类型的情况下实现循环法

时间:2013-11-04 09:37:12

标签: 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 个答案:

答案 0 :(得分: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,那么这个对象是可变的,你只能在可变的val和不可变的vars之间做出选择。 (你也可以使用指向可变结构的变量,但为什么要这样做呢?)

另一方面,您也可以选择完全不同的方法:

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的对象可以再次是可变的或不可变的。

答案 1 :(得分:0)

进行了一些细微的改动,以便在执行三次以上的时候交替使用该类,如提供的示例所示。

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