Tenho problemas com o seguinte código:
func generic1<T>(name : String){
}
func generic2<T>(name : String){
generic1<T>(name)
}
o resultado genérico1 (nome) para erro do compilador "Não é possível especializar explicitamente uma função genérica"
Existe alguma maneira de evitar esse erro? Não posso alterar a assinatura da função genérica1, portanto, deve ser (String) -> Void
T
usado emgeneric1()
? Como você chamaria essa função, para que o compilador possa inferir o tipo?func foo<T>() -> T { ... }
isso faz algo com um objetot
do tipoT
e o retornot
. Especializar-T
se explicitamente permitiriat1
inferir emvar t1 = foo<T>()
. Eu gostaria que houvesse uma maneira de chamar funções dessa maneira também. C # permiteRespostas:
Eu também tive esse problema e encontrei uma solução alternativa para o meu caso.
Neste artigo o autor tem o mesmo problema
https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide
Portanto, o problema parece ser que o compilador precisa inferir o tipo de T de alguma forma. Mas não é permitido simplesmente usar <type> genérico (params ...).
Normalmente, o compilador pode procurar o tipo de T, examinando os tipos de parâmetro porque é onde T é usado em muitos casos.
No meu caso foi um pouco diferente, porque o tipo de retorno da minha função era T. No seu caso, parece que você não usou T em sua função. Eu acho que você simplificou o código de exemplo.
Portanto, tenho a seguinte função
E no caso de, por exemplo
o compilador me dá o erro:
Portanto, para dar ao compilador outra fonte de informação para inferir o tipo de T, você deve declarar explicitamente o tipo da variável em que o valor de retorno é salvo.
Dessa forma, o compilador sabe que T deve ser um inteiro.
Portanto, acho que, no geral, significa simplesmente que, se você especificar uma função genérica, terá que usar pelo menos T em seus tipos de parâmetro ou como um tipo de retorno.
fonte
func updateProperty<T>( propertyID : String )
let value = foo() as? Type
para que pudesse ser usado em umif
ouguard
o resultado é opcional, mas não ...Swift 5
Normalmente, existem muitas maneiras de definir funções genéricas. Mas eles são baseados na condição que
T
deve ser usada como umparameter
, ou como umreturn type
.Depois disso, devemos fornecer
T
ao ligar.Ref:
fonte
self.result = UIViewController.doSomething()
funciona por conta própria, desde que você tenha digitado a propriedade ao declará-la.doLastThing<UITextView>()
se torna SwiftdoLastThing(UITextView.self)
, o que não é ... o pior, pelo menos. Melhor do que ter que digitar explicitamente resultados complicados. Obrigado pela solução alternativa.A solução é usar o tipo de classe como parâmetro (como em Java)
Para deixar o compilador saber com que tipo ele está lidando, passe a classe como argumento
Ligue como:
fonte
Você não precisa de uma função genérica aqui, já que tem tipos estáticos (String como parâmetro), mas se quiser que uma função genérica chame outra, você pode fazer o seguinte.
Usando métodos genéricos
Usando uma classe genérica (menos flexível, pois o genérico pode ser definido para 1 tipo apenas por instância)
fonte
Eu acho que quando você especifica a função genérica, você deve especificar alguns dos parâmetros do tipo T, como segue:
e se quiser chamar o método handle (), você pode fazer isso escrevendo protocolo e especificando a restrição de tipo para T:
então você pode chamar esta função genérica com String:
e vai compilar
fonte
Até agora, minha melhor prática pessoal usou a resposta de @orkhan-alikhanov. Hoje, quando se olha para SwiftUI e como
.modifier()
eViewModifier
é implementado, eu encontrei outra maneira (ou é mais uma solução alternativa?)Basta envolver a segunda função em um
struct
.Exemplo:
Se este fornecer a você a mensagem "Não é possível especializar explicitamente uma função genérica"
Este pode ajudar. Envolva a declaração de
generic1
em umstruct
:e chamá-lo com:
Observações:
struct
é um bom exemplo. A solução alternativa aqui não tem um pouco mais de informação - mas passa pelo compilador. Mesma informação, mas resultados diferentes? Então algo está errado. Se for um bug do compilador, ele pode ser corrigido.fonte
Tive um problema semelhante com minha função de classe genérica
class func retrieveByKey<T: GrandLite>(key: String) -> T?
.Eu não poderia chamá-lo
let a = retrieveByKey<Categories>(key: "abc")
onde Categories é uma subclasse de GrandLite.let a = Categories.retrieveByKey(key:"abc")
GrandLite retornou, não categorias. As funções genéricas não inferem o tipo com base na classe que as chama.class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T?
deu-me um erro quando tentei,let a = Categories.retrieveByKey(aType: Categories, key: "abc")
deu-me um erro informando que não foi possível converter Categories.Type em GrandLite, embora Categories seja uma subclasse de GrandLite. CONTUDO...class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T?
fez o trabalho se eu tentasselet a = Categories.retrieveByKey(aType: [Categories](), key: "abc")
, aparentemente, uma atribuição explícita de uma subclasse não funciona, mas uma atribuição implícita usando outro tipo genérico (array) funciona em Swift 3.fonte
aType
como uma instância deT
, em vez de se colocarCategories
. Ex:let a = Categories.retrieveByKey(aType: Categories(), key: "abc")
. Outra solução é definiraType: T.Type
. Em seguida, chame o método comolet a = Categories.retrieveByKey(aType: Categories.self, key: "abc")