creating a new instance of a type in scala

后端 未结 3 1140
春和景丽
春和景丽 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条回答
  • 2021-02-04 14:11

    You can demand an implicit parameter, like so:

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

    All you need then is to have an implicit factory of the desired type in scope when you instanciate A, e.g. the following works:

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

    As shown by:

    scala> a.t
    res22: Seq[String] = List()
    
    0 讨论(0)
  • 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")
    
    0 讨论(0)
  • 2021-02-04 14:22

    The same as @Raphael's answer with a case class's apply method:

    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)
      }
    }
    
    0 讨论(0)
提交回复
热议问题