2011-03-14 117 views
9

创建类型的新实例。如果我有一个C类定义为在斯卡拉

class C[A] 

有没有什么方法来创建的C之内A一个新的实例?就像

class C[A] { 
    def f(): A = new A() 
} 

我明白,如果这是可能的,你可能必须在某处指定构造函数参数,这很好。

如果不可能,是否有任何设计模式用于处理您想要创建类型的新实例的情况?

+0

和你有什么建议,如果具体情况类型没有(无参数)构造器? – Raphael 2011-03-14 19:14:24

+0

理想情况下,你可以在类型参数中指定它。所以我可以将C定义为'class C [A(String,String)]'或其他东西。然后我必须用两个String参数来调用A. – 2011-03-14 20:46:48

+0

这是有效的Scala吗? – Raphael 2011-03-16 11:43:50

回答

10

你可以使用一个类型的类抽象实例:

trait Makeable[T] { 
    def make: T 
} 

class C[T: Makeable] { 
    def f(): T = implicitly[Makeable[T]].make 
} 

例如,

implicit object StringIsMakeable extends Makeable[String] { 
    def make: String = "a string" 
} 

val c = new C[String] 
c.f // == "a string" 

当你实例C,你需要提供明示或暗示,一个Makeable那将充当适当类型的工厂。当然,该工厂将负责在调用构造函数时提供任何构造函数参数。

或者,你可以使用一个清单,但被警告,这种方法依赖于反射,而不是安全型:

class C[T: Manifest] { 
    def f(): T = manifest[T].erasure.newInstance.asInstanceOf[T] 
} 

为了完整起见,你也可以轻松地扩展这种方法来传递一些或全部的到化妆方法构造函数的参数:

trait Makeable[Args, T] { def make(a: Args): T } 

class C[Args, T](implicit e: Makeable[Args, T]) { 
    def f(a: Args): T = e.make(a) 
} 

// some examples 
case class Person(firstName: String, lastName: String) 

implicit val personFactory1 = new Makeable[(String, String), Person] { 
    def make(a: (String, String)): Person = Person(a._1, a._2) 
} 
implicit val personFactory2 = new Makeable[String, Person] { 
    def make(a: String): Person = Person(a, "Smith") 
} 

val c1 = new C[String, Person] 
c1.f("Joe") // returns Person("Joe", "Smith") 

val c2 = new C[(String, String), Person] 
c2.f("John", "Smith") // returns Person("John", "Smith") 
5

您可以要求一个隐含参数,像这样:

class A[T](implicit newT : T) { 
    val t = newT 
} 

您需要的全部内容是当您在实例A(例如)中创建具有所需类型的隐式工厂时。以下工作:

implicit def newSeq[T] = Seq[T]()     
val a = new A[Seq[String]]        

如通过:

scala> a.t 
res22: Seq[String] = List() 
1

同为@拉斐尔的回答与案件类的apply方法:

class Container[A](contained: A) 
case class Person(name: String) 
case class PersonContainer(person: Person) extends Container[Person](person) 
implicit def _ = PersonContainer.apply _ 

class Creator { 
    def deserializeAndPackage[A, B <: Container[A]](data: Array[Byte]) 
          (implicit containerCreator: (A => B)): B = { 
    val p = /* deserialize data as type of A */ 
    containerCreator(p) 
    } 
}