2013-11-04 36 views
1

我目前正试图找到我的方式进入斯卡拉的世界。其实我试图实现没有可变类型的循环策略。斯卡拉 - 实现无可变类型的循环法

我有一个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中不可改变的队列,但我真的不知道如何与不变类型解决这个问题。不知何故,我将不得不记得索引权?那种使用不可变类型没有意义的情况之一是什么?

+1

你能否澄清OptHosts(具体是它的类型)? –

+0

当然,将它添加到示例代码中。 – MeiSign

回答

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和不可变变量之间进行选择。 (当然你也可以有指向可变结构瓦尔,但为什么要这么做?)

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

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

+0

多数民众赞成真棒!感谢您的回答 – MeiSign

+0

第一种方法应该在写入时进行同步,否则在var可能不当的多线程环境中进行同步。阅读由队列的不变性保证 –

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