【问题标题】:How can I remove this extra type parameter?如何删除这个额外的类型参数?
【发布时间】:2012-12-03 14:07:01
【问题描述】:

我目前有:

class X[+T: Numeric](val x: T)
abstract class M[N: Numeric, T <: X[N]] { // <- I'd like to remove N.
  def apply(x: Int): T
  final def row = (1 to 10).map(this(_))
}

我是这样使用的:

class Y(x: Double, val y: Double) extends X[Double](x)
class Z extends M[Double, Y] {           // <- So that this is simpler.
  def apply(x: Int) = new Y(0.0, 0.0)
}

它是这样工作的:

object testapp {
  // row is properly polymorphic, allowing access to Y.y
  def main(args: Array[String]): Unit = (new Z).row.map(r => println(r.y))
}

我希望Z 更简单,以便我可以使用M 喜欢:

class Z extends M[Y] {
  def apply(x: Int) = new Y(0.0, 0.0)
}

或者,甚至更好:

class Z extends M[Double] {           // i.e. Meaning apply can return
  def apply(x: Int) = new Y(0.0, 0.0) // any subclass of X[Double]
}

Here are my Gist iterations 到达这一点。

【问题讨论】:

    标签: scala generics covariance


    【解决方案1】:

    类型参数与类型成员的第三种方法是同时使用两者。

    类型成员的一个优点是它不会污染子类的签名。如果类型成员是多余的(即使在具体类中),它也可以保持抽象;并且只有底层类必须在必要时定义它。

      import scala.collection.immutable.IndexedSeq
      class X[+T: Numeric](val x: T)
      abstract class M[+A: Numeric] {
        type W <: X[A]
        def apply(x: Int): W
        final def row: IndexedSeq[W] = (1 to 10) map apply
        def sumx: A = {  // in terms of the underlying Numeric
          val n = implicitly[Numeric[A]]
          n fromInt (0 /: row)((s,w) => s + (n toInt w.x))
        }
      }
    
      class Y(x: Double, val y: Double) extends X[Double](x)
      class Z extends M[Double] {
        type W = Y
        def apply(x: Int) = new Y(0.0, 0.0)
      }
    
      def main(args: Array[String]): Unit = (new Z).row foreach (Console println _.y)
    

    【讨论】:

    • 选择了因为最直接地回答了这个问题。谢谢。你能为我澄清一下吗?我将其解读为:type W &lt;: X[A] 在M 中定义了一个类型W,使得W 是X[A] 的子类型。那么在M 的子类型中,W 被“覆盖”为M 的子类型所需的类型?
    • 有了绑定,类型 W 仍然是抽象的,所以定义它时不需要覆盖。 (像任何其他成员一样。)(规范 4.3。另外,请注意 stackoverflow.com/a/10223364/1296806.)
    【解决方案2】:

    你在这里并不需要class M:

    class X[+T: Numeric](val x: T)
    def row[W <: X[_]](c: => Int => W) = (1 to 10).map(c)
    
    class Y(x: Double, val y: Double) extends X[Double](x)
    def z = row(_ => new Y(0.0, 0.0))
    
    def main(args: Array[String]): Unit = z.map(r => println(r.y))
    

    如果你想保留M,你用同样的想法:

    class X[+T: Numeric](val x: T)
    abstract class M[W <: X[_]] {
        def apply(x: Int): W
        final def row = (1 to 10).map(this(_))
    }
    
    class Y(x: Double, val y: Double) extends X[Double](x)
    class Z extends M[Y] {
      def apply(x: Int) = new Y(0.0, 0.0)
    }
    
    def main(args: Array[String]): Unit = (new Z).row.map(r => println(r.y))
    

    【讨论】:

    • 感谢您的回答,但目标不是消除M。我想我需要它(但我正在考虑你的替代方案)。这是一个更大的解决方案的一部分。这个想法是M 是一个只能包含由X[T] 界定的类型的集合,其中T 是Numeric。我创建了几个M 的子类来封装针对元素的不同功能。
    • 您可以创建几个函数,例如 z,而不是几个子类。如果不了解更大的解决方案,我可能会错过一些东西,但我认为 OO 封装在这里是开销。
    • 函数方法的问题是M 实际上是一个类型,特别是一个集合。但我认为你可能是对的,我应该提供对单个参数化类型M 进行操作的函数,而不是对M 进行子类化。您的答案有一个问题是X[_]。 _ 是 Any 但我需要 Numeric。
    • 它不会与在范围内没有实现 Numeric 类型类的 X[T] 一起编译。用'class StringX(x: String) extends X[String](x)'检查它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-18
    • 2011-07-10
    • 2014-09-16
    • 2015-08-06
    • 2010-10-23
    相关资源
    最近更新 更多