Подтвердить что ты не робот

Невозможно явно выделить обобщенную функцию

У меня проблема со следующим кодом:

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

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

результат generic1 (name) для ошибки компилятора "Не может явно специализировать общую функцию"

Можно ли избежать этой ошибки? Я не могу изменить подпись функции generic1, поэтому она должна быть (String) → Void

4b9b3361

Ответ 1

У меня также была эта проблема, и я нашел обходное решение для моего дела.

В этой статье автор имеет ту же проблему

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

Таким образом, проблема заключается в том, что компилятор должен каким-то образом вывести тип T. Но не допускается просто использовать общий <type> (params...).

Обычно компилятор может искать тип T, просматривая типы параметров, потому что во многих случаях используется T.

В моем случае это было немного иначе, потому что возвращаемый тип моей функции был T. В вашем случае кажется, что вы вообще не использовали T в своей функции. Я думаю, вы просто упростили код примера.

Итак, у меня есть следующая функция

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

И в случае, например,

getProperty<Int>("countProperty")

компилятор дает мне

Cannot explicitly specialize a generic function

Итак, чтобы дать компилятору другой источник информации, чтобы вывести тип T, вы должны явно объявить тип переменной, в которой сохраняется возвращаемое значение.

var value : Int = getProperty("countProperty")

Таким образом, компилятор знает, что T должен быть целым числом.

Итак, я думаю, что в целом это просто означает, что если вы укажете общую функцию, вам нужно хотя бы использовать T в ваших типах параметров или в качестве типа возврата.

Ответ 2

Решение принимает тип класса как параметр (например, в Java)

Чтобы компилятор знал, какой тип он имеет дело с передачей класса в качестве аргумента

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)
    }
}

Вызов как:

self.navigate(UserDetailsViewController.self, id: "UserDetailsViewController", before: {
        controller in
        controller.user = self.notification.sender
    })

Ответ 3

Swift 4.2

Как правило, существует множество способов определения общих функций. Но они основаны на условии, что T должен использоваться как parameter или как 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
    }
}

После этого мы должны предоставить T при звонке.

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

Ответ 4

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

Использование общих методов

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
} 

Использование универсального класса (Менее гибкий как общий может быть определен для 1 типа только для каждого экземпляра)

class Foo<T> {

   func doStuff(text: String) -> T {
      return doOtherStuff(text)
   }

   func doOtherStuff(text: String) -> T {

   }  

}

let foo = Foo<Int>()
foo.doStuff("text")

Ответ 5

Я думаю, что когда вы укажете общую функцию, вы должны указать некоторые параметры типа T, например:

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

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

и если вы хотите вызвать метод handle(), вы можете сделать это, написав протокол и указав ограничение типа для 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)
}

чтобы вы могли вызвать эту общую функцию со String:

generic2("Some")

и он скомпилирует

Ответ 6

У меня была аналогичная проблема с моей общей функцией класса class func retrieveByKey<T: GrandLite>(key: String) -> T?.

Я не мог назвать его let a = retrieveByKey<Categories>(key: "abc"), где Категории являются подклассом GrandLite.

let a = Categories.retrieveByKey(key:"abc") вернулся GrandLite, а не категории. Общие функции не вызывают тип, основанный на классе, который их вызывает.

class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T? дал мне ошибку, когда я попробовал let a = Categories.retrieveByKey(aType: Categories, key: "abc") дал мне ошибку, что он не смог преобразовать категории .Type в GrandLite, хотя категории - это подкласс GrandLite. ОДНАКО...

class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T? работал, если я пробовал let a = Categories.retrieveByKey(aType: [Categories](), key: "abc"), очевидно, что явное назначение подкласса не работает, но неявное присвоение с использованием другого родового типа (массива) работает в Swift 3.

Ответ 7

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!) {...}