Him*_*hra 1 generics scala invariants covariant
所以这是代码:
package week4
object expr {
abstract class Expr[T] {
def eval:T = this match {
case Number(x) => x
case Sum(e1, e2) => e1.eval + e2.eval
}
def show: String = this match {
case Number(x) => "" + x
case Sum(e1, e2) => "(" + e1.show + "+" + e2.show + ")"
}
}
case class Number[T](val value: T) extends Expr {
}
case class Sum[T](val e1: Expr[T], val e2: Expr[T]) extends Expr {
}
}
Run Code Online (Sandbox Code Playgroud)
除了我得到所有案例比较的错误:
构造函数无法实例化为期望的类型; 发现:week4.expr.Number [T(在类Number中)] required:week4.expr.Expr [T(在类Expr中)]注意:Nothing <:T(和week4.expr.Number [T] <:week4. expr.Expr [Nothing]),但类Expr在类型T中是不变的.您可能希望将T定义为+ T.
我究竟做错了什么?
ste*_*ino 12
您的代码中主要有两个错误:
Expr时忘记传递类型参数Sum模式匹配的分支中,您试图将两个Ts 相加,而没有向编译器提供足够的证据证明+在类型上定义了运算符T.这是一个有效的修订解决方案:
object expr {
abstract class Expr[T](implicit evidence: Numeric[T]) {
def eval: T = this match {
case Number(x) => x
case Sum(e1, e2) => evidence.plus(e1.eval, e2.eval)
}
def show: String = this match {
case Number(x) => "" + x
case Sum(e1, e2) => "(" + e1.show + "+" + e2.show + ")"
}
}
case class Number[T : Numeric](val value: T) extends Expr[T]
case class Sum[T : Numeric](val e1: Expr[T], val e2: Expr[T]) extends Expr[T]
}
Run Code Online (Sandbox Code Playgroud)
以下是Scala shell中的示例:
scala> import expr._
import expr._
scala> Sum(Sum(Number(2), Number(3)), Number(4))
expression: expr.Sum[Int] = Sum(Sum(Number(2),Number(3)),Number(4))
scala> println(expression.show + " = " + expression.eval)
((2+3)+4) = 9
Run Code Online (Sandbox Code Playgroud)
我确定类型构造函数缺少的类型参数Expr只是一个分心,它不需要进一步解释.
我的示例中的代码引入了隐式参数evidence和Numeric类型类的用法.在Scala中,类型类是一种模式,它利用特征和隐式参数来定义具有一定灵活性的类的功能.
为了对两个通用值求和,编译器必须有办法知道两者T知道如何求和.但是,数字类型不在类型层次结构中,可以通过说这T是一个假设类的子类型Number(通过编写类似的东西abstract class Expr[T <: Number])来利用它.
然而,Scala标准库引入了Numeric类型类,它基本上是一个特征,它定义了一组对所有数字类型都有意义的操作(因此名称).plus对于想要遵守这种特性的人来说,该方法是未实现的.
Scala标准库为各种数字类型实现了这种特性,因此您可以毫不费力地使用各种类型的相同通用实现.
这是一个例子:
scala> val expression = Sum(Sum(Number(2.0), Number(3.0)), Number(4.0))
expression: expr.Sum[Double] = Sum(Sum(Number(2.0),Number(3.0)),Number(4.0))
scala> println(expression.show + " = " + expression.eval)
((2.0+3.0)+4.0) = 9.0
Run Code Online (Sandbox Code Playgroud)
指定这样的隐式证据可以显式地(如在abstract class Expr[T](implicit evidence: Numeric[T]))中或通过使用所谓的"上下文绑定"表示法(如在case class Number[T : Numeric])中进行,这基本上是显式变体的语法糖,它放弃了显式引用类型类实例.我在第一种情况下使用了显式变体,因为我需要在我的代码中引用类型类实例来实际求和两个值(evidence.plus(e1.eval, e2.eval))但在后一种情况下我使用了"上下文绑定"符号,因为我觉得它更自然和可读.
如果您愿意,还可以为Numeric[T]自己的类(例如:) 实现,Numeric[Rational]而无需处理静态类型层次结构.
这当然是类型类的一个非常仓促的解释:为了更彻底的解释,我建议你这篇关于这个主题的非常好的博客文章.
| 归档时间: |
|
| 查看次数: |
491 次 |
| 最近记录: |