在Scala中实例化参数化类

时间:2014-12-22 05:20:32

标签: scala generics instantiation

我有一个Operator抽象类:

abstract class Operator[T, U] {
  def setParent(op: Operator[T, U]): Unit

  def newOp(): Operator[Byte, String] = {
    val newOperator = new NewOperator[Byte, String]
    newOperator.setParent(this)
    newOperator
  }
}

和另一个NewOperator

class NewOperator[T, U] extends Operator[T, U] {
  var parent: Operator[T,U] = null
  def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}

现在,在课程newOp()的{​​{1}}方法的第二行,我收到错误

Operator

说:newOperator.setParent(this) ^

解决此问题的唯一方法是将Type mismatch: expected: Operator[Byte, String], actual: Operator[T, U]添加到.instanceOf[Operator[Byte, String]]吗?

this

3 个答案:

答案 0 :(得分:1)

为什么不让方法newOp通用?

abstract class Operator[T, U] {
  def setParent(op: Operator[T, U]): Unit

  def newOp(): Operator[T, U] = {
    val newOperator = new NewOperator[T, U]
    newOperator.setParent(this)
    newOperator
  }
}

class NewOperator[T, U] extends Operator[T, U] {
  var parent: Operator[T,U] = null
  def setParent(op: Operator[T, U]): Unit = {this.parent = op}
}

val op = new NewOperator[Byte, String]().newOp

答案 1 :(得分:1)

您当前的解决方案限制所有运算符[Byte,String]具有Operator [Byte,String]父类型(如果您使用asInstanceOf,则只能在运行时找到它)。

一般情况下,如果父/子泛型类型可能不同,请使用:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Operator[T, U, P <: Operator[_, _, _]] { 
  var parent: P = null.asInstanceOf[P]
  def setParent(op: P): Unit = {this.parent = op}
  def newOp[TT, UU]() = {
    val newOperator = new Operator[TT, UU, Operator[T, U, P]]()
    newOperator.setParent(this)
    newOperator
   }
}


// Exiting paste mode, now interpreting.

defined class Operator

scala> new Operator[Byte, String, Null]
res19: Operator[Byte,String,Null] = Operator@5470e2f4

scala> res19.newOp[Int, String]
res20: Operator[Int,String,Operator[Byte,String,Null]] = Operator@729c1e43

scala> res20.parent
res21: Operator[Byte,String,Null] = Operator@5470e2f4

如果您需要为运营商提供一些特定的状态/方法,您可以将newOp移动到某个子类并使运营商成为特征。

或者您可以将类型类用于特定于操作员的操作:

scala> new Operator[Byte, String, Null]
res23: Operator[Byte,String,Null] = Operator@728b49e2

scala> implicit class ByteOperator(o: Operator[Byte, String, _]) {
     |         def hello = "hello" //here you can access some members of Operator
     |     }
defined class ByteOperator

scala> res23.hello
res24: String = hello

如果您确实需要与父母具有相同通用性的孩子:

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Operator[T, U] {
  var parent: Operator[T, U] = null
  def newInstance: Operator[T, U] = new Operator[T, U]
  def newOp: Operator[T, U] = {
      val newOperator = newInstance
      newOperator.setParent(this)
      newOperator
  }
  def setParent(op:  Operator[T, U]): Unit = {this.parent = op}
}


// Exiting paste mode, now interpreting.

defined class Operator

scala> new Operator[Byte, String]
res15: Operator[Byte,String] = Operator@4e6ea769

scala> res15.newOp
res16: Operator[Byte,String] = Operator@c774157

scala> res16.parent
res17: Operator[Byte,String] = Operator@4e6ea769

如果你只需要建模一些AST(抽象语法树),case classess可能是一个很好的解决方案:

trait Expression[T] {       
     def v: T
}

case class Value[T](v: T) extends Expression[T] 

case class Plus[T1, T2](a: Expression[T1], b: Expression[T2])(implicit wrap: T1 => Arithmetic[T1, T2]) extends Expression[T1] {
    def v = wrap(a.v) ++ b.v
}

abstract class Arithmetic[T1, T2](v: T1) {
     def ++ (v: T2): T1
}

implicit class ArithmeticInt(val v: Int) extends Arithmetic[Int, Int](v) {
     def ++ (v2: Int) = v + v2
} 

implicit class ArithmeticIntDouble(val v: Int) extends Arithmetic[Int, Double](v) {
     def ++ (v2: Double) = (v.toDouble + v2).toInt
} 

scala> Plus(Value(5.0), Value(11.0)).v
res57: Value[Double] = Value(16.0)

scala> Plus(Value(5), Value(11.0)).v
res67: Int = 16

scala> Plus(Value(5), Value(6)).v
res68: Int = 11

scala> Plus(Value(5.0), Value(6)).v
<console>:60: error: No implicit view available from Double => Arithmetic[Double,Int].
              Plus(Value(5.0), Value(6)).v
                  ^

答案 2 :(得分:0)

而不是像这样做

 newOperator.setParent(this) in abstract class operator you can do something like this

 newOperator.setParent(newOperator)

这将解决您的问题