scala map方法无法正确解析具有固定函数类型的集合中的函数类型

时间:2016-10-10 17:02:06

标签: scala

我有以下代码,

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))
                                                ^

感谢您让我知道这里出了什么问题。

1 个答案:

答案 0 :(得分:2)

函数在参数类型中不具有协变性(它们实际上是逆变的)。 这意味着,如果FooBar的子类,则Foo => Unit 不是 Bar => Unit的子类(反之亦然)。< / p>

在您的情况下,您试图强制func1func2强制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)