Passing a type parameter for instantiation

后端 未结 2 1576
清歌不尽
清歌不尽 2021-01-24 15:02

Why wouldn\'t the scala compiler dig this:

class Clazz

class Foo[C <: Clazz] {
  val foo = new C  
}

class type required but C found
[error]   val a = new C         


        
相关标签:
2条回答
  • 2021-01-24 15:20

    I came up with this scheme, couldn't simplify it through a companion object thought.

    class Clazz
    class ClazzFactory {
      def apply = new Clazz
    }
    
    class Foo(factory: ClazzFactory) {
      val foo: Clazz = factory.apply
    }
    

    It's very annoying that ClazzFactory can't be an object rather than a class though. A simplified version:

    class Clazz {
      def apply() = new Clazz
    }
    
    class Foo(factory: Clazz) {
      val foo: Clazz = factory.apply
    }
    

    This requires the caller to use the new keyword in order to provide the factory argument, which is already a minor enough annoyance relative to the initial problem. But, scala could have made this scenario all more elegant; I had to fallback here to passing a parameter of the type I wish to instantiate, plus the new keyword. Maybe there's a better way.

    (motivation was to instantiate that type many times within the real Foo, that's why this is at all a solution; otherwise my pattern above is just redundantly meaningless).

    0 讨论(0)
  • 2021-01-24 15:35

    This is a classic generic problem that also happens in Java - you cannot create an instance of a generic type variable. What you can do in Scala to fix this, however, is to introduce a type evidence to your type parameter that captures the runtime type:

    class Foo[C <: Clazz](implicit ct: ClassTag[C]) {
        val foo = ct.runtimeClass.newInstance
    }
    

    Note that this only works if the class has a constructor without any arguments. Since the parameter is implicit, you don't need to pass it when calling the Foo constructor:

    Foo[Clazz]()
    
    0 讨论(0)
提交回复
热议问题