我有以下代码,
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列表包含只有String => Unit或Int => Unit的函数),代码可以工作,但是当运行选项3时,我收到错误:
:68: error: type mismatch;
found : Int with String => Unit
required: Any => Unit
inputArgs.map(x => obsKPI(x._1, x._2))
^
感谢您让我知道这里出了什么问题。
答案 0 :(得分:2)
函数在参数类型中不具有协变性(它们实际上是逆变的)。
这意味着,如果Foo
是Bar
的子类,则Foo => Unit
不是 Bar => Unit
的子类(反之亦然)。< / p>
在您的情况下,您试图强制func1
和func2
强制Any => 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 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)