2015-01-13 22 views
1

我已經定義了下面的對象。但我不明白爲什麼mapValues只能在test1中執行。即。爲什麼是輸出:返回選項時mapValues中的奇怪行爲

調用TEST1

調用TEST2

映射:一個

映射:兩個

映射:映射(1 - > XX,2 - > XX )

我用scala 2.10和2.11 w來測試它ith同樣的結果。

object Test { 

    def test1: Option[String] = { 

     val map = Map(1 -> "One", 2 -> "Two") 
     val mapped = map.mapValues { v => 
      println("Mapping: " + v) 
      "Xx" 
     } 
     None 
    } 

    def test2: Option[String] = { 

     val map = Map(1 -> "One", 2 -> "Two") 
     val mapped = map.mapValues { v => 
      println("Mapping: " + v) 
      "Xx" 
     } 
     println("Mapped: " + mapped) 
     None 
    } 



    def main(args: Array[String]): Unit = { 

     println("Calling test1") 
     test1 
     println("Calling test2") 
     test2 
    } 

} 

回答

1

對方回答解釋了這個問題,但作爲一個解決方案,如果你想有一個嚴格的地圖,只要使用普通的map

val m = Map(1 -> "One", 2 -> "Two") 
val mapped = m.map { 
    case (k,v) => k -> { 
    println("Mapping: " + v) 
    "Xx" 
    } 
} 

或者,您也可以定義自己的擴展方法做你想要什麼:

import scala.collection.GenTraversableLike 
import scala.collection.generic.CanBuildFrom 
implicit class HasMapVals[T, U, Repr](val self: GenTraversableLike[(T, U), Repr]) extends AnyVal { 
    def mapVals[R, That](f: U => R)(implicit bf: CanBuildFrom[Repr, (T, R), That]) = { 
    self.map { case (k,v) => k -> f(v) } 
    } 
} 

val m = Map(1 -> "One", 2 -> "Two") 
val mapped = m.mapVals { v => 
    println("Mapping: " + v) 
    "Xx" 
} 
2

mapValues的實際返回view,所以結果懶洋洋地計算。從scaladoc爲mapValues

返回此映射的至f每個鍵(在此(密鑰))映射的映射圖。結果地圖包裝原始地圖而不復制任何元素。

因此,例如:

val mapped = Map(1 -> "One", 2 -> "Two").mapValues { v => 
    println("Mapping: " + v) 
    "Xx" 
} 

在它自己的聲明時會打印出什麼。但只要訪問mapped,就會計算這些值,並且將打印報表。 (事實上​​,該值將被重新計算一次訪問mapped

Test.test1,沒有什麼訪問mapped,所以值不會計算。

Test.test2中,您打印出mapped,這會觸發值的計算。

+0

並說我想強制mapValues。推薦的方式是什麼? – user79074

+0

@ user79074您可以在'mapValues'之後鏈接'.view.force'來強制執行評估。或者使用@dhg建議的嚴格地圖。 –