我正在尝试选择一些Scala,并且在我发现函数的有趣功能中 通用(输入类型)?特别有用。但是,尝试以下代码,
def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)
我收到了下面写的恼人错误:
<console>:8: error: type mismatch;
found : List[A]
required: List[String]
def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail.asInstanceOf[List[A]], base)
如何在类型推理系统中提出A == String并抛出此异常。难道我完全错误地使用了这种结构吗?
THX
答案 0 :(得分:1)
问题是您为泛型类型A调用+。编译器尝试推断使用+的内容(如String),并且您得到错误。我也不了解你想用+。
实现的目标答案 1 :(得分:1)
您不能保证方法+
可用于A
类型。因此,编译器将A
转换为String
。
一种解决方案包括使用类型类。
trait Addable[A] {
def plus(x: A, y: A): A
}
recFunc[A:Addable]…
您可以在这里查看尖顶,简介:http://typelevel.org/blog/2013/07/07/generic-numeric-programming.html
答案 2 :(得分:1)
您在+
上调用了A
方法,但无法保证A
有这样的方法。有两种方法可以解决这个问题:继承或类型类。
通过继承,找到包含所需方法的所有所需类的共同祖先是一件简单的事情,然后编写[A <: CommonAncestor]
。不幸的是,由于努力使Scala与Java和一般JVM限制互操作,数字原语并没有共享这样的祖先。
然后,我们离开了类型类。表达式“类型类”来自Haskell,其思想是您可以将不同类型分组到一个共享一些常见属性的类中。它与继承之间的主要区别在于类型类对扩展是开放的:您可以轻松地将任何类型添加到这样的类中。
Scala没有直接类型类支持。相反,我们使用“类型类模式”来模拟它。基本上,我们创建一个类 - 类型类 - 包含我们想要的方法。接下来,我们为每个我们希望支持的类型创建该类的实例。最后,我们通过隐式传递这些实例,这使得编译器的工作就是找到所需的实例。
在您的示例中,我们可以这样做:
// Our type class
class Addable[T] {
def plus(a: T, b: T): T
}
// Or Int instance
object AddableInt {
class AddableInt extends Addable[Int] {
def plus(a: Int, b: Int): Int = a + b
}
implicit val addableInt = new AddableInt
}
// Make the implicit available
import AddableInt._
// Make recFunc use it
def recFunc[A](xs: List[A], base : () => A)(implicit addable: Addable[A]): A =
if (xs.isEmpty) base() else addable.plus(xs.head, recFunc(xs.tail, base))
// call recFunc
recFunc(List(1, 2, 3), () => 0)
有许多方法可以改进这一点,例如使用隐式类和上下文边界。有关implicits和上下文边界的更多信息,请参阅Stack Overflow上的Scala wiki(分别为会话23和19)。
现在,Scala已经具有基本算术的上下文边界,甚至还有一些额外的技巧使用视图边界来使其无缝使用。以下是单独使用标准库的方法:
import scala.math.Numeric.Implicits._
def recFunc[A : Numeric](xs: List[A], base : ()=>A) : A =
if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)
另请参阅Numeric scaladoc,尽管它的示例非常低。