создание нового экземпляра типа в Scala - PullRequest
9 голосов
/ 14 марта 2011

Если у меня есть класс C, определенный как

class C[A]

Есть ли способ создать новый экземпляр A в C? Что-то вроде

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

Я понимаю, что если бы это было возможно, вам, вероятно, пришлось бы где-то указывать аргументы конструктора, и это нормально.

Если это невозможно, есть ли шаблоны проектирования для решения ситуаций, в которых вы хотите создать новый экземпляр типа?

Ответы [ 3 ]

10 голосов
/ 14 марта 2011

Вы можете использовать класс типов для абстрагирования экземпляров:

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

Для полноты вы также можете легко расширить этот подход, чтобы передать некоторые или все параметры конструктора в метод make:

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 голосов
/ 14 марта 2011

Вы можете запросить неявный параметр, например, так:

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 голос
/ 10 августа 2014

То же, что и ответ @ Рафаэля с методом 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)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...