2016-10-10 50 views
1

我有以下代碼,階映射方法不能正確地解析功能類型中收集與固定功能類型

def obsKPI[T](kpi: Option[T], f: T => Unit) = { 
    kpi match { 
     case Some(obsValue) => f(obsValue) 
     case _ => Unit 
    } 
} 

def func1(str:String):Unit = println(str) 
def func2(num: Int):Unit = println(num) 

//option1: val inputArgs = List((Some("first"),(func1 _)),(Some("third"), (func1 _))) 
//option2: val inputArgs = List((Some(456), (func2 _)),(None,(func2 _))) 
// option3: 
val inputArgs = List((Some("first"),(func1 _)),(Some(456), (func2 _)),(Some("third"), (func1 _)),(None,(func2 _))) 

inputArgs.map(x => obsKPI(x._1, x._2)) 

運行任一選項1或2時(在inputArgs列表僅包含字符串的功能=>單位或INT =>單元),代碼工作,但運行選項3時,我得到一個錯誤:

:68: error: type mismatch; 
found : Int with String => Unit 
required: Any => Unit 
       inputArgs.map(x => obsKPI(x._1, x._2)) 
               ^

謝謝你讓我知道什麼地方出了問題在這裏。

回答

2

函數在它們的參數類型中不是協變的(它們實際上是逆變的)。 這意味着,如果FooBar一個亞類中,Foo => UnitBar => Unit一個子類(正好相反)。

在你的情況,你想強迫func1func2Any => Unit,但不能工作,因爲它們的類型不兼容 - 一個是String => Unit,另一種是Int => Unit。要解決這個問題

的一種方法,是使用一個案例類,而不是一個元組:

case class KPI[T](t: Option[T], f: T => Unit) 
def obsKPI(kpi: KPI[_]) = kpi match { 
    case KPI(Some(k), f) => f(k) 
    case _ =>() // `()` is the value of type Unit. Unit, as you had it is the value of type Unit.type - not what you want at all 
} 
// You can also write the above more concise like this: def obsKPI[T](kpi: KPI[T]) = kpi.t.foreach(kpi.f) 

def func1(str:String) = println(str) 
def func2(num: Int) = println(num) 

val inputArgs = List(KPI(Some("first"),func1 _), KPI(Some(456), func2 _), KPI(Some("third"), func1 _), KPI[Int](None,func2 _)) 

inputArgs.foreach(obsKPI) // Could do .map here too, but ending up with a list of()s is unlikely what you you want. 

你可以,如果你讓你的obsKPI看起來更優雅一點,進入的一員case class:

case class KPI[T](t: Option[T], f: T => Unit) { 
    def obs = t.foreach(f) 
} 
val inputArgs = List(KPI(Some("first"),func1 _), KPI(Some(456), func2 _), KPI(Some("third"), func1 _), KPI[Int](None,func2 _)) 

inputArgs.foreach(_.obs) 
+0

根據源代碼「final abstract class Int private extends AnyVal」。 AnyVal再次延伸Any。至少我應該正常工作,如果我註釋掉def func1(str:String)? – BDR

+0

'Int'是'Any'的一個子類,是的。但是'Int => Unit''不是'Any => Unit'的子類 如果你刪除了'func1',並且只在所有地方留下'func2',那麼這將起作用,因爲'inputArgs'將會是'List [Int, Int => Unit]',所以'obsKPI'調用中的'T'將會解析爲'Int'而不是'Any' – Dima

+0

yes yes使敏感 – BDR