2013-11-04 50 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 
     } 
    }