How can I invoke the constructor of a Scala abstract type?

后端 未结 3 763
攒了一身酷
攒了一身酷 2021-02-14 17:11

I\'m trying to figure out how to invoke a constructor for a Scala abstract type:

class Journey(val length: Int)
class PlaneJourney(length: Int) extends Journey(l         


        
相关标签:
3条回答
  • 2021-02-14 17:29

    There is no direct way to invoke the constructor or access the companion object given only a type. One solution would be to use a type class that constructs a default instance of the given type.

    trait Default[A] { def default: A }
    
    class Journey(val length: Int)
    object Journey {
      // Provide the implicit in the companion
      implicit def default: Default[Journey] = new Default[Journey] {
        def default = new Journey(0)
      }
    }
    
    class Port[J <: Journey : Default] {
      // use the Default[J] instance to create the instance
      def startJourney: J = implicitly[Default[J]].default
    }
    

    You will need to add an implicit Default definition to all companion objects of classes that support creation of a default instance.

    0 讨论(0)
  • 2021-02-14 17:39

    My inclination is that this cannot be done. I am far from a Scala guru, but my reasoning is this:

    1. You have a class Port with a type argument T where T must inherit from Journey (but T does not have to be exactly Journey, this is important).
    2. Within Port, you define a method which creates a new T. This class has no idea what T is, and therefore what T's constructor looks like.
    3. Because you don't know what arguments T's constructor takes, you don't know what arguments to pass to it.

    The solutions to this problem are handled very nicely in another question, so I will point you there for them rather than repeating here: Abstract Types / Type Parameters in Scala

    0 讨论(0)
  • 2021-02-14 17:44

    Your class needs an implicit constructor parameter to get the Manifest. Then you can call erasure to get the Class and call newInstance, which reflectively calls the nullary constructor if there is one.

    class J[A](implicit m:Manifest[A]) {
      def n = m.erasure.newInstance()
    }
    
    new J[Object].n
    

    As of Scala 2.10, the erasure property in the manifest is deprecated. def n = m.runtimeClass.newInstance() does the same thing, but without warnings.

    0 讨论(0)
提交回复
热议问题