É mais fácil explicar o problema em um exemplo. Por exemplo, considere esta classe genérica simples:
final class GenericClass<T> {
private let parameter: T
init(parameter: T) {
self.parameter = parameter
}
}
Quero adicionar um vazio init
em uma extensão, quando T
for any Array
(ou mesmo Collection
, mas não é crucial para o meu caso). Quero algo assim, mas não compila:
// Reference to generic type 'Array' requires arguments in <...>
extension GenericClass where T: Array {
convenience init() {
// Cannot convert value of type '[Any]' to expected argument type 'T'
self.init(parameter: [])
}
}
Como posso adicionar um parâmetro genérico ao Array
? Esta sintaxe não funciona:
extension GenericClass<U> where T: Array<U> { // Cannot find type 'U' in scope
convenience init() {
self.init(parameter: [U]()) // Cannot call value of non-function type '[Any]'
}
}
( T == Array<U>
também não funciona.)
Existe alguma maneira de conseguir o que descrevi? Eu realmente gostaria de evitar declarar extensões separadas para cada tipo de elemento que preciso (claro que o código abaixo funciona perfeitamente):
extension GenericClass where T == [Int] {
convenience init() {
self.init(parameter: [])
}
}
Se você precisar especificamente de
Array
, você pode adicionar o parâmetro de tipo extraU
aoinit
. em vez deextension GenericClass<U>
:Se tudo o
init
que você precisa é poder converter[]
paraT
.T
pode ser apenas algo que sejaExpressibleByArrayLiteral
.Se por
[]
você especificamente quer dizer "uma coleção vazia", então você deve exigirT
que sejaRangeReplaceableCollection
. Este protocolo fornece uminit
que cria uma coleção vazia.Não é o caso que
ExpressibleByArrayLiteral
implica que o tipo é uma coleção.OptionSet
por exemplo, não é umCollection
, mas éExpressibleByArrayLiteral
.