2015-09-26 3 views
1

Почему Скала компилятор не будет копать так:Передача параметра типа для конкретизации

class Clazz 

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

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

Связанные вопрос - How to get rid of : class type required but T found

+0

Не могли бы вы обновить свой пример, чтобы имена соответствовали и имели смысл? – Clashsoft

+0

Готово, извинения. Теперь мы можем удалить наш комментарий. – matanster

ответ

2

Это классическая общая проблема, которая также происходит в Java - вы не можете создать экземпляр переменной общего типа. Что вы можете сделать в Scala, чтобы исправить это, однако, ввести тип доказательства для вашего типа параметра, который захватывает тип выполнения:

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

Обратите внимание, что это работает только, если класс имеет конструктор без каких-либо аргументов. Поскольку параметр подразумевается, что вам не нужно, чтобы передать его при вызове конструктора Foo:

Foo[Clazz]() 
+0

- это не случай конструктора без каких-либо аргументов, а ограниченное подмножество, чтобы наслаждаться этим решением? – matanster

+2

Если вы не передадите параметры, я не вижу, как что-то еще может работать. Если вы хотите иметь больше опций, я бы предложил использовать заводское решение или напрямую передать значение поля. – Clashsoft

+0

После реализации обоих способов, возможно, трудно решить, что на самом деле более уродливо. Значение набирается компилятором как 'Any', а не как' C', что неизбежно, потому что класс определяется методом runtimeClass'. Если в моем предложенном ответе есть противоположное, но очень похожее искажение, которого нельзя избежать. Мне трудно даже назвать этот тип безопасным. Как грустно. – matanster

0

Я придумал эту схему, не могли бы упростить ее через объект компаньон мысли.

class Clazz 
class ClazzFactory { 
    def apply = new Clazz 
} 

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

Это очень раздражает, что ClazzFactory не может быть объектом, а не классом. Упрощенная версия:

class Clazz { 
    def apply() = new Clazz 
} 

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

Это требует, чтобы вызывающий использовать новое ключевое слово для того, чтобы обеспечить заводскую аргумент, который уже второстепенный достаточно раздражением по отношению к исходной задаче. Но Scala мог сделать этот сценарий более элегантным; Мне пришлось вернуться сюда, чтобы передать параметр типа, который я хотел бы создать, плюс ключевое слово new. Может быть, есть лучший способ.

(мотивация заключалась в том, чтобы создать экземпляр этого типа много раз в пределах реального Foo, вот почему это вообще не решение, иначе мой шаблон выше просто лишним).

Смежные вопросы