为什么不';泛型类型在Scala中是否与继承一起工作?

为什么不';泛型类型在Scala中是否与继承一起工作?,scala,generics,invariants,covariant,Scala,Generics,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

下面是代码:

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 {
  }
}
除了我得到的所有案例比较的错误:

无法将构造函数实例化为预期类型;已找到:week4.expr.Number[T(类内编号)]必填项:week4.expr.expr.expr[T(类内编号)]
类Expr)]注意:没有您的代码中主要有两个错误:

  • 扩展
    Expr
    时忘记传递类型参数
  • 在模式匹配的
    Sum
    分支中,您试图对两个
    T
    s求和,但没有向编译器提供足够的证据证明
    +
    运算符是在类型
    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]

}
下面是在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
我确信类型构造函数
Expr
缺少类型参数只是一种干扰,不需要进一步解释

我的示例中的代码引入了一个隐式参数
证据
数值
类型类的用法。在Scala中,类型类是一种模式,它利用特征和隐式参数来定义具有一定灵活性的类的功能


为了求两个泛型值的和,编译器必须知道两个
T
s知道如何求和。但是,数字类型不在类型层次结构中,可以通过说
T
是假设类
Number
的子类型来利用它(通过编写类似
abstract class Expr[T的内容,代码中主要有两个错误:

  • 扩展
    Expr
    时忘记传递类型参数
  • 在模式匹配的
    Sum
    分支中,您试图对两个
    T
    s求和,但没有向编译器提供足够的证据证明
    +
    运算符是在类型
    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]

}
下面是在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
我确信类型构造函数
Expr
缺少类型参数只是一种干扰,不需要进一步解释

我的示例中的代码引入了一个隐式参数
证据
数值
类型类的用法。在Scala中,类型类是一种模式,它利用特征和隐式参数来定义具有一定灵活性的类的功能


为了求两个泛型值的和,编译器必须知道两个
T
s知道如何求和。但是,数字类型不在类型层次结构中,可以通过说
T
是假设类
Number
的子类型(通过编写类似
抽象类Expr[T还建议除了类型类之外,还应该阅读类型差异。@3jckd当然,在处理类型层次结构时,它可能会成为一个非常重要的主题。如果您碰巧阅读了什么是类型差异,但最终不理解它,那么这张图是我个人最喜欢的一张,可能会有所帮助:
new
关键字c当实例化像
Sum
Number
这样的case类时,可能会忽略一个,或者我遗漏了什么?@isaias-b你完全正确,因为编译器为case类生成了一个伴生对象,而
apply
方法是构造函数的快捷方式。谢谢你的提示,我会立即编辑回复。你也会这样做吗除了类型类之外,建议阅读类型差异。@3jckd绝对,在处理类型层次结构时,它可能会成为一个非常重要的主题。如果您碰巧阅读了什么是类型差异,但最终不理解它,则此图像是我的个人最爱,可能会有所帮助:
new
关键字可以省略当实例化像
Sum
Number
这样的case类时,或者我遗漏了什么?@isaias-b你完全正确,因为编译器为case类生成了一个伴随对象,使用
apply
方法作为构造函数的快捷方式。谢谢你的提示,我会立即编辑回复。如果提供的答案是有效的,如果你能把它标记为接受就好了。:-)花了我的甜蜜时光。迟做总比不做好。:)谢谢!如果提供的答案是有效的,如果你能把它标记为接受就好。:-)花了我的甜蜜时光。迟做总比不做好。:)谢谢!