Unable to explicitly allocate a generic function

I have a problem with the following code:

func generic1<T>(name : String){ } func generic2<T>(name : String){ generic1<T>(name) } 

the result of generic1 (name) for a compiler error "Cannot explicitly specialize a general function"

Can this error be avoided? I cannot change the signature of the generic1 function, so it should be (String) -> Void

+67
generics swift
Jan 15 '15 at 14:17
source share
7 answers

I also had this problem and I found a workaround for my case.

In this article, the author has the same problem.

https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide

So the problem is that the compiler must somehow infer the type T. But you are not allowed to just use the generic <type> (params ...).

Typically, the compiler can search for type T by looking at parameter types, because in many cases T. is used.

In my case, it was a little different, because the return type of my function was T. In your case, it seems that you did not use T in your function at all. I think you just simplified the example code.

So I have the following function

 func getProperty<T>( propertyID : String ) -> T 

And in the case of, for example,

 getProperty<Int>("countProperty") 

the compiler gives me

 Cannot explicitly specialize a generic function 

So, in order to give the compiler a different source of information in order to infer the type T, you must explicitly declare the type of the variable in which the return value is stored.

 var value : Int = getProperty("countProperty") 

Thus, the compiler knows that T must be an integer.

So, I think that overall it just means that if you specify a generic function, you need to at least use T in your parameter types or as a return type.

+122
Jun 11 '15 at 18:32
source share

The decision takes the class type as a parameter (for example, in Java)

So that the compiler knows what type it deals with passing the class as an argument

 extension UIViewController { func navigate<ControllerType: UIViewController>(_ dump: ControllerType.Type, id: String, before: ((ControllerType) -> Void)?){ let controller = self.storyboard?.instantiateViewController(withIdentifier: id) as! ControllerType before?(controller) self.navigationController?.pushViewController(controller, animated: true) } } 

Call as:

 self.navigate(UserDetailsViewController.self, id: "UserDetailsViewController", before: { controller in controller.user = self.notification.sender }) 
+16
Nov 18 '16 at 11:09
source share

Swift 4.2

Typically, there are many ways to define common functions. But they are based on the condition that T should be used as a parameter or as a return type .

 extension UIViewController { class func doSomething<T: UIView>() -> T { return T() } class func doSomethingElse<T: UIView>(value: T) { // Note: value is a instance of T } class func doLastThing<T: UIView>(value: T.Type) { // Note: value is a MetaType of T } } 

After that, we must provide T when calling.

 let result = UIViewController.doSomething() as UIImageView // Define 'T' by casting, as UIImageView let result: UILabel = UIViewController.doSomething() // Define 'T' with property type, as UILabel UIViewController.doSomethingElse(value: UIButton()) // Define 'T' with parameter type, as UIButton UIViewController.doLastThing(value: UITextView.self) // Define 'T' with parameter type, as UITextView 

Ref:

  1. http://austinzheng.com/2015/01/02/swift-generics-pt-1/
  2. https://dispatchswift.com/type-constraints-for-generics-in-swift-d6bf2f0dbbb2
+15
Apr 15 '17 at 5:51 on
source share

Here you do not need a generic type, since you have static types (String as parameter), but if you want the generic function to call another, you could do the following.

Using common methods

 func fetchObjectOrCreate<T: NSManagedObject>(type: T.Type) -> T { if let existing = fetchExisting(type) { return existing } else { return createNew(type) } } func fetchExisting<T: NSManagedObject>(type: T.Type) -> T { let entityName = NSStringFromClass(type) // Run query for entiry } func createNew<T: NSManagedObject>(type: T.Type) -> T { let entityName = NSStringFromClass(type) // create entity with name } 

Using a generic class (Less flexible as generic can be defined for type 1 for each instance only)

 class Foo<T> { func doStuff(text: String) -> T { return doOtherStuff(text) } func doOtherStuff(text: String) -> T { } } let foo = Foo<Int>() foo.doStuff("text") 
+3
Jul 11 '15 at 21:29
source share

I think that when you specify a generic function, you should specify some parameters of type T, for example:

 func generic1<T>(parameter: T) { println("OK") } func generic2<T>(parameter: T) { generic1(parameter) } 

and if you want to call the handle () method, you can do this by writing a protocol and specifying a type constraint for T:

 protocol Example { func handle() -> String } extension String: Example { func handle() -> String { return "OK" } } func generic1<T: Example>(parameter: T) { println(parameter.handle()) } func generic2<T: Example>(parameter: T) { generic1(parameter) } 

so you can call this generic function with String:

 generic2("Some") 

and he will compile

+2
Apr 14 '15 at 13:39 on
source share

I had a similar problem with my generic class function class func retrieveByKey<T: GrandLite>(key: String) -> T? .

I could not call it let a = retrieveByKey<Categories>(key: "abc") , where Categories are a subclass of GrandLite.

let a = Categories.retrieveByKey(key:"abc") returned GrandLite, not a category. General functions do not call a type based on the class that calls them.

class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T? gave me an error when I tried let a = Categories.retrieveByKey(aType: Categories, key: "abc") gave me an error that it could not convert .Type categories to GrandLite, although the categories are a subclass of GrandLite. HOWEVER...

class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T? worked if i tried let a = Categories.retrieveByKey(aType: [Categories](), key: "abc") , it is obvious that explicit subclass assignment does not work, but implicit assignment using another generic type (array) works in Swift 3.

0
Oct 29 '16 at 2:00
source share
 class UploadResult: Parsable{ ... } func upload<T:Parsable>(type: T.Type, image: UIImage, success:@escaping (_ error:ApiError?, _ result:T?)->Void ) {...} UploadApi.upload(type: UploadResult.self, image: imageForUpload.image!) {...} 
-four
May 12 '18 at 14:29
source share



All Articles