如何调用Scala抽象类型的构造函数?

时间:2011-09-30 22:27:59

标签: scala

我试图弄清楚如何为Scala抽象类型调用构造函数:

class Journey(val length: Int)
class PlaneJourney(length: Int) extends Journey(length)
class BoatJourney(length: Int) extends Journey(length)

class Port[J <: Journey] {
  def startJourney: J = {
    new J(23) // error: class type required but J found
  }
}

这甚至可行吗?我熟悉Scala manifests,但我不清楚他们如何在这里提供帮助。同样,我无法弄清楚如何使用伴随对象的apply()构造函数来做同样的事情:

object Journey { def apply() = new Journey(0) }
object PlaneJourney { def apply() = new PlaneJourney(0) }
object BoatJourney { def apply() = new BoatJourney(0) }

class Port[J <: Journey] {
  def startJourney: J = {
    J() // error: not found: value J
  }
}

感激地收到任何想法!

3 个答案:

答案 0 :(得分:7)

您的类需要一个隐式构造函数参数来获取Manifest。然后你可以调用erasure来获取Class并调用newInstance,如果有的话,它会反过来调用nullary构造函数。

class J[A](implicit m:Manifest[A]) {
  def n = m.erasure.newInstance()
}

new J[Object].n

从Scala 2.10开始,不推荐使用清单中的erasure属性。 def n = m.runtimeClass.newInstance()做同样的事情,但没有警告。

答案 1 :(得分:7)

没有直接的方法来调用构造函数或仅在给定类型的情况下访问伴随对象。一种解决方案是使用构造给定类型的默认实例的类型类。

trait Default[A] { def default: A }

class Journey(val length: Int)
object Journey {
  // Provide the implicit in the companion
  implicit def default: Default[Journey] = new Default[Journey] {
    def default = new Journey(0)
  }
}

class Port[J <: Journey : Default] {
  // use the Default[J] instance to create the instance
  def startJourney: J = implicitly[Default[J]].default
}

您需要向支持创建默认实例的类的所有伴随对象添加隐式Default定义。

答案 2 :(得分:0)

我的倾向是,这是无法做到的。我离斯卡拉大师很远,但我的理由是这样的:

  1. 你有一个带有类型参数T的类Port,其中T必须从Journey继承(但T不必完全 Journey,这很重要)。
  2. 在Port中,您定义了一个创建新T的方法。这个类不知道T是什么,因此T的构造函数是什么样的。
  3. 因为您不知道T的构造函数采用什么参数,所以您不知道传递给它的参数。
  4. 这个问题的解决方案在另一个问题上得到了很好的处理,所以我会在那里指出你而不是在这里重复:Abstract Types / Type Parameters in Scala