creating a new instance of a type in scala

后端 未结 3 1144
春和景丽
春和景丽 2021-02-04 13:41

If I have a class C defined as

class C[A]

is there any way to create a new instance of A within C? Something like



        
3条回答
  •  闹比i
    闹比i (楼主)
    2021-02-04 14:20

    You could use a type class to abstract instantiation:

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

    For example,

    implicit object StringIsMakeable extends Makeable[String] {
       def make: String = "a string"
    }
    
    val c = new C[String]
    c.f // == "a string"
    

    When you instantiate C, you'll need to provide, explicitly or implicitly, a Makeable that will act as a factory of the appropriate type. That factory, of course, would be responsible for supplying any constructor arguments when it invokes the constructor.

    Alternatively, you could use a Manifest, but be warned that this approach relies on reflection and is not type safe:

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

    For completeness, you can also easily extend this approach to pass some or all of the constructor parameters in to the make method:

    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")
    

提交回复
热议问题