2011-09-30 57 views
8

我试图找出如何调用构造函数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,但我不清楚他们在这里可以如何帮助。同样我无法弄清楚如何做同样的同伴对象的适用()构造函数:

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 
    } 
} 

任何想法感激地接受!

回答

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定义添加到支持默认实例的创建类的所有同伴的对象。

+0

谢谢莫里茨 - 但是将代码粘贴到REPL中会引发一些错误?另外如何将参数添加到默认的“构造函数”? –

+0

您必须为此代码输入粘贴模式才能在REPL中工作(只需在粘贴前键入':paste')即可。 Philippe修复的代码也存在错误。 – Moritz

+1

如果你想添加参数,你可以简单地在'Default'特性中添加一个新的方法。 '默认[J]]'会给你一个带有提供的类型参数的特性实例,你可以调用你喜欢的任何方法,例如, '隐式[默认[J]]。创建(23)'。请参阅示例[此问题](http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits)以了解有关隐含工作的详细信息。 – Moritz

0

我的倾向是,这是不能做到的。我是远从Scala的大师,但我的推理是这样的:

  1. 你有一类口岸有一个类型参数T,其中T必须从旅程继承(但T没有要正好之旅,这很重要)。
  2. 在Port中,您定义了一个创建新T的方法。该类不知道T是什么,因此T的构造函数看起来像什么。
  3. 因为你不知道T的构造函数需要什么参数,所以你不知道传递给它的参数。

这个问题的解决方案中的另一个问题非常漂亮的处理,所以,我会为你在那里为他们而不是在此重复:Abstract Types/Type Parameters in Scala

7

类别需要一个隐含的构造函数的参数,以获得Manifest。然后你可以调用擦除来得到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()做同样的事情,但没有警告。

+0

这种方法不需要无参数的构造函数吗? –

+0

@Chris它的确如此,这就是限制。除非你为任何需要的工厂制造特质。 –

+0

谢谢金 - 很高兴有newInstance()“构造函数”明确解释 –