Scala多态函数将编译但不会按预期运行

时间:2017-06-05 16:09:20

标签: scala parametric-polymorphism

鉴于以下两个Scala函数,两者都按预期编译。

scala> def toList[A](a: A) = List(a)
toList: [A](a: A)List[A]

scala> def foo[A](f: A => List[A], b: A) = f(b)
foo: [A](f: A => List[A], b: A)List[A]

然而,当你运行它时,它给出了以下错误消息:

scala> foo(toList, 12)
<console>:14: error: type mismatch;
 found   : Nothing => List[Nothing]
 required: Int => List[Int]
       foo(toList, 12)

为什么Scala认为toList函数属于Nothing => List[Nothing]而不是Int => List[Int]

2 个答案:

答案 0 :(得分:1)

根据foo的定义,foo(12, toList)传递参数是错误的。正确的方法是foo(toList, 12)

  
    

为什么Scala认为toList函数是Nothing =&gt;列出[Nothing]而不是Int =&gt;列表[INT]?

  

12属于Int类型,因为foo

def foo[A](f: A => List[A], b: A) = f(b)

它还期望A类型,Int函数也是toList

如果您将foo称为foo(toList, 12D),我们会收到以下错误

<console>:22: error: type mismatch;
 found   : Nothing => List[Nothing]
 required: Double => List[Double]
       foo(toList, 12D)

因为12DDouble typetoList预计也是Double

所以正确的方法是

foo(toList[Any], 12)

答案 1 :(得分:1)

Scala编译器会尝试推断方法的类型参数,它将查看第一个括号中定义的参数并尝试从中提取类型,如果不能,则会选择下一个参数组来推断类型,等等...

定义该功能的最佳方法是这样的

def foo[A](b: A)(f: A => List[A]) = f(b)

按此顺序给出参数将允许您避免向compliler提供一些提示。您可以像这样调用此函数:

foo(2.0d)(toList)

你会得到一个List [Double]

如果你保留另一个顺序,你需要给编译器一个提示,以便找出类型参数A

foo(toList[Double], 2.0d)