【问题标题】:Scala - Implement round robin without mutable typesScala - 实现没有可变类型的循环
【发布时间】:2013-11-04 09:37:12
【问题描述】:

我目前正在尝试进入 Scala 世界。实际上,我正在尝试实现没有可变类型的循环策略。

我有一个 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 中的不可变队列,但我真的不知道如何用不可变类型解决这个问题。不知何故,我必须记住一个索引,对吗?这是使用不可变类型没有意义的情况之一吗?

【问题讨论】:

  • 你能澄清一下 OptHosts(特别是它的类型)吗?
  • 当然,把它添加到示例代码中。

标签: scala round-robin


【解决方案1】:

如果我每次在对象上调用执行时我都理解正确,它应该使用不同的元素。然后因为对象要封装状态,所以没有办法绕过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 和不可变 var 之间进行选择。 (你也可以有指向可变结构的变量,但你为什么要这样做?)

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

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

【讨论】:

  • 太棒了!谢谢你的回答
  • 第一种方法应该在写入时同步,否则在多线程环境中 var 可能会出现异常。队列的不变性保证了读取
【解决方案2】:

进行了细微的更改,以便类现在在执行超过 3 次(如提供的示例中所示)时轮流进行。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-09-01
    • 2012-04-10
    • 2015-03-09
    相关资源
    最近更新 更多