我正在通過Odersky,Spoon和Venners編寫Scala第二版編程,這個例子讓我感覺到了一個循環,因爲它似乎違背了我認爲的功能編程的真實性,不變性。在這個例子中(以及第18章的書中較早的部分),作者聲稱,即使這些操作可能在內部改變對象的狀態,對象上的操作仍然可以是「純粹的功能」。這個例子在第442頁上, 19,是這樣的:在Scala中編程的功能隊列
class Queue[+T] private (
private[this] var leading: List[T],
private[this] var trailing: List[T]
) {
private def mirror() =
if (leading.isEmpty) {
while (!trailing.isEmpty) {
leading = trailing.head :: leading
trailing = trailing.tail
}
}
def head: T = {
mirror()
leading.head
}
def tail: Queue[T] = {
mirror()
new Queue(leading.tail, trailing)
}
def enqueue[U >: T](x: U) =
new Queue[U](leading, x :: trailing)
}
給出的理由是,只要副作用對客戶端不可見,像這樣的東西可以被認爲是功能性的。我想我可以在後面...我的意思是嚴格地說,這是什麼定義了一個函數。但不可否認(我對JVM內存模型保證的內容並不是很瞭解),但是在這段代碼中沒有潛在的問題嗎?
例如,如果兩個線程都在這個隊列,它看起來像這樣運行的操作開始:
Leading: Nil
Trailing: List(1,2,3,4)
是不是有可能,一個線程可以調用頭()獲得在鏡子這一點()被取消調度之前:
private def mirror() =
if (leading.isEmpty) {
while (!trailing.isEmpty) {
leading = trailing.head :: leading
> trailing = trailing.tail
}
}
在該點處的隊列看起來像這樣:
Leading: List(1)
Trailing: List(1,2,3,4)
而當第二個線程調用尾(),而首先是不活躍,這將返回:
Leading: Nil
Trailing: List(1,2,3,4)
而如果第一個線程的頭()調用來完成,這將在隨後尾後退還
Leading: List(2,3,4)
Trailing: Nil
我固然沒有這樣的東西,併發編程是真正mindbending對我來說,因爲我相信這是很多人,我是偉大的:()名單上調用只是好奇我在這裏錯過了什麼。
我認爲你是對的。我想你可以說,如果它被多個線程使用,那麼「功能性感覺」就會崩潰。功能程序應該是無縫併發的嗎?我不知道。 – Owen