我正在嘗試轉換java.util.StringTokenizer
為 Scala Iterator
,但以下方法失敗:
def toIterator(st: StringTokenizer): Iterator[String] =
Iterator.continually(st.nextToken()).takeWhile(_ => st.hasMoreTokens()))
但這有效:
def toIterator(st: StringTokenizer): Iterator[String] =
Iterator.fill(st.countTokens())(st.nextToken())
您可以在 Scala 控制臺中看到這一點:
scala> Iterator("a b", "c d").map(new java.util.StringTokenizer(_)).flatMap(st => Iterator.continually(st.nextToken()).takeWhile(_ => st.hasMoreTokens())).toList
res1: List[String] = List(a, c)
scala> Iterator("a b", "c d").map(new java.util.StringTokenizer(_)).flatMap(st => Iterator.fill(st.countTokens())(st.nextToken())).toList
res2: List[String] = List(a, b, c, d)
如您所見res1
,這是不正確的并且res2
是正確的。我究竟做錯了什么?第一個版本應該可以作業并且是首選,因為它比第二種方法快 2 倍,因為它不會掃描字串兩次
uj5u.com熱心網友回復:
takeWhile
不打算有狀態地使用。它應該采用一個純函式,僅根據輸入來確定是否繼續。
具體來說,迭代器必須在呼叫謂詞之前產生值。即使您的函式忽略了引數,它仍然會被評估。所以被呼叫,然后我們檢查更多的令牌。takeWhile
takeWhile
nextToken
準確地說,在你的"a b"
情況下,
- 首先,我們呼叫
nextToken
,這是做什么Iterator.continually
的。有一個下一個令牌,所以它回傳"a"
。 - 現在,為了確定我們是否應該包含下一個標記,我們將您的謂詞
"a"
稱為引數。您的謂詞忽略"a"
并呼叫hasMoreTokens
. 我們的標記器有更多標記(即"b"
),所以它回傳 true。繼續。 - 現在我們
nextToken
再次打電話。這回傳"b"
。 - 我們需要確定是否應該將其包含在結果中,因此我們的
takeWhile
謂詞使用"b"
as 引數運行。我們的takeWhile
謂詞忽略它的引數并呼叫hasMoreTokens
。我們沒有更多的代幣了,所以回傳false
. 我們不應該包括這個元素。 takeWhile
回傳了 false,所以我們停在它回傳 true 的最后一個元素。我們的結果串列是List("a")
。
由于我們濫用了一種純粹的函式式技術,比如takeWhile
有狀態,我們得到了不直觀的結果。
盡管擁有一個單行解決方案看起來很時髦和聰明,但您擁有的是一個有狀態的命令式物件,您希望它適應Iterator
介面。在一堆純函式呼叫中隱藏這種狀態并不是一個好主意,所以我們應該撰寫自己的子類Iterator
并正確執行。
import java.util.StringTokenizer
final class StringTokenizerIterator(
private val tokenizer: StringTokenizer
) extends Iterator[String] {
def hasNext: Boolean = tokenizer.hasMoreTokens
def next(): String = tokenizer.nextToken()
}
object Example {
def toIterator(st: StringTokenizer): Iterator[String] =
new StringTokenizerIterator(st)
def main(args: Array[String]) = {
println(Iterator("a b", "c d")
.map(new java.util.StringTokenizer(_))
.flatMap(toIterator(_))
.toList)
}
}
我們正在做與呼叫適當StringTokenizer
函式時相同的作業,但我們是在一個封裝狀態的完整類中進行的,而不是假裝有狀態部分不存在。它是更長的代碼,是的,但它應該更長。我們不希望它的混亂部分被忽視。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/508573.html
標籤:斯卡拉