3 回答

TA貢獻1793條經驗 獲得超6個贊
對于理解將轉換為對mapor flatMap方法的調用。例如這個:
for(x <- List(1) ; y <- List(1,2,3)) yield (x,y)
變成:
List(1).flatMap(x => List(1,2,3).map(y => (x,y)))
因此,第一個循環值(在本例中為List(1))將接收flatMap方法調用。由于flatMap在List返回另一個List,的的理解,結果當然會是一個List。(這對我來說是新的:因為理解并不總是導致信息流,甚至不一定會導致Seqs。)
現在,看看如何flatMap在中聲明Option:
def flatMap [B] (f: (A) ? Option[B]) : Option[B]
請記住這一點。讓我們看看如何將理解錯誤(帶有的錯誤Some(1))轉換為一系列map調用:
Some(1).flatMap(x => List(1,2,3).map(y => (x, y)))
現在,很容易看到該flatMap調用的參數是按要求返回a List而不是返回的東西Option。
為了解決問題,您可以執行以下操作:
for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y)
這樣編譯就可以了。值得注意的是,Option它不是Seq通常所假定的的子類型。

TA貢獻1818條經驗 獲得超11個贊
一個容易記住的技巧,因為理解會嘗試返回第一個生成器的集合類型,在這種情況下為Option [Int]。因此,如果從Some(1)開始,則應該期望Option [T]的結果。
如果要獲取列表類型的結果,則應從列表生成器開始。
為什么有此限制,而不假定您總是需要某種順序?您可能會遇到需要返回的情況Option。也許你有一個Option[Int]你想要的東西結合起來,得到一個Option[List[Int]],用下面的函數說:(i:Int) => if (i > 0) List.range(0, i) else None; 然后,您可以編寫此代碼,并在事情沒有“意義”時得到None:
val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None
for (i <- Some(5); j <- f(i)) yield j
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4))
for (i <- None; j <- f(i)) yield j
// returns: Option[List[Int]] = None
for (i <- Some(-3); j <- f(i)) yield j
// returns: Option[List[Int]] = None
實際上,如何擴展理解力實際上是將類型的對象M[T]與函數組合(T) => M[U]以獲得類型的對象的相當通用的機制M[U]。在您的示例中,M可以是Option或List。通常,它必須是相同的類型M。因此,您不能將Option與List結合使用。有關可能存在的其他情況的示例M,請查看此特征的子類。
為什么結合List[T]與(T) => Option[T]工作雖然當你開始與列表?在這種情況下,庫在有意義的地方使用更通用的類型。因此,您可以將List與Traversable結合使用,并且存在從Option到Traversable的隱式轉換。
底線是:考慮要讓表達式返回哪種類型,并以該類型作為第一個生成器開始。如有必要,將其包裝為該類型。
- 3 回答
- 0 關注
- 630 瀏覽
添加回答
舉報