2011-03-14 168 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) 
    } 
}