Generics 无法显式专门化泛型函数

Generics 无法显式专门化泛型函数,generics,swift,Generics,Swift,我对以下代码有异议: func generic1<T>(name : String){ } func generic2<T>(name : String){ generic1<T>(name) } func generic1(名称:String){ } func generic2(名称:字符串){ 一般1(姓名) } 编译器错误“无法显式专门化泛型函数”的generic1(名称)结果 有没有办法避免这个错误?我不能更改generic1函数的签名

我对以下代码有异议:

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

func generic2<T>(name : String){
     generic1<T>(name)
}
func generic1(名称:String){
}
func generic2(名称:字符串){
一般1(姓名)
}
编译器错误“无法显式专门化泛型函数”的generic1(名称)结果


有没有办法避免这个错误?我不能更改generic1函数的签名,因此它应该是(String)->Void

我认为当您指定generic函数时,您应该指定一些类型为t的参数,如下所示:

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

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

它将编译

我也有这个问题,我为我的案例找到了解决办法

在本文中,作者也有同样的问题

所以问题似乎是,编译器需要以某种方式推断T的类型。但不允许简单地使用泛型(params…)

通常情况下,编译器可以通过扫描参数类型来查找T的类型,因为在许多情况下,这是使用T的地方

在我的例子中有点不同,因为我函数的返回类型是T。在你的例子中,你似乎根本没有在函数中使用T。我猜您只是简化了示例代码

所以我有下面的函数

func getProperty<T>( propertyID : String ) -> T
这样编译器就知道T必须是整数


所以我认为总的来说,这仅仅意味着如果你指定了一个泛型函数,你必须至少在你的参数类型中使用T或者作为返回类型

这里不需要泛型,因为您有静态类型(字符串作为参数),但是如果您想让泛型函数调用另一个函数,可以执行以下操作

使用通用方法

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
} 
func fetchObjectOrCreate(类型:T.type)->T{
如果let existing=fetchExisting(类型){
返回现有的
}
否则{
返回createNew(类型)
}
}
func fetchExisting(类型:T.type)->T{
让entityName=NSStringFromClass(类型)
//运行实体查询
} 
func createNew(类型:T.type)->T{
让entityName=NSStringFromClass(类型)
//创建具有名称的实体
} 
使用泛型类(灵活性较低,因为每个实例只能为1个类型定义泛型)

class-Foo{
func doStuff(文本:字符串)->T{
返回doOtherStuff(文本)
}
func doOtherStuff(文本:字符串)->T{
}  
}
设foo=foo()
foo.doStuff(“文本”)

我的泛型类函数
类函数retrieveByKey(key:String)->T?
也有类似的问题

我不能称之为
let a=retrieveByKey(key:“abc”)
,其中Categories是GrandLite的子类

let a=Categories.retrieveByKey(键:“abc”)
返回的是GrandLite,而不是Categories。泛型函数不会根据调用它们的类推断类型

class-func-retrieveByKey(aType:T,key:String>)->T?
在我尝试
let a=Categories时给了我一个错误。retrieveByKey(aType:Categories,key:abc”)
给了我一个错误,它无法将Categories.Type转换为GrandLite,即使Categories是GrandLite的子类。然而

class func retrieveByKey(aType:[T],key:String)->T?
如果我尝试
let a=Categories.retrieveByKey(aType:[Categories](),key:abc”)
显然子类的显式赋值不起作用,但是使用另一个泛型类型(数组)的隐式赋值在Swift 3中工作。

解决方案将类类型作为参数(如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)
    }
}
斯威夫特5 通常有许多方法来定义泛型函数。但它们基于的条件是
T
必须用作
参数
,或者用作
返回类型

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
    }
}
参考:


  • 到目前为止,我个人的最佳实践使用了@orkhan alikhanov的答案。今天,当我研究SwiftUI以及如何实现
    .modifier()
    ViewModifier
    时,我找到了另一种方法(或者它更像是一种解决方法?)

    只需将第二个函数包装到
    结构中

    例子: 如果这个函数给出“不能显式专门化泛型函数”

    并称之为:

    func generic2<T>(name : String){
         Generic1Struct<T>().generic1(name: name)
    }
    
    func generic2(名称:String){
    Generic1Struct().generic1(名称:name)
    }
    
    评论:
    • 我不知道在任何可能的情况下,当这个错误消息发生时,它是否有帮助。我只知道,当这件事发生时,我被困了很多次。我确实知道,当出现错误消息时,这个解决方案在今天起到了作用
    • 斯威夫特处理泛型的方式对我来说仍然令人困惑
    • 这个例子和
      结构的变通方法是一个很好的例子。这里的解决方法没有更多的信息,而是通过编译器。相同的信息,但不同的结果?那就有问题了。如果它是一个编译器错误,它可以得到修复

    当无法根据上下文推断泛型类型时,在此处使用泛型类型有什么意义?如果泛型类型仅在内部使用,则应在函数体中指定类型。在
    generic1()
    中是否使用了占位符类型
    T
    ?你将如何调用该函数,以便编译器可以推断类型?我希望有某种方法可以调用像genetic1(“SomeString”)这样的函数泛型,而不仅仅适用于编译器可以推断上下文的情况。明确地专门化函数将允许推断代码的其他部分。例如:
    func foo()->T{…}
    对类型为
    T
    的对象
    T
    执行操作,并返回
    T
    。明确专门化
    T
    将允许在
    var t1=foo()
    中推断
    t1
    。我希望有一种方法也能这样调用函数。C#允许我也遇到了这件事。如果强制将类型作为参数传递,则创建泛型函数毫无意义。这一定是个虫子,对吧?!节省了我很多时间。谢谢。有w吗
    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
    } 
    
    class Foo<T> {
    
       func doStuff(text: String) -> T {
          return doOtherStuff(text)
       }
    
       func doOtherStuff(text: String) -> T {
    
       }  
    
    }
    
    let foo = Foo<Int>()
    foo.doStuff("text")
    
    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
        })
    
    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
        }
    }
    
    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
    
    func generic2<T>(name: String){
         generic1<T>(name)
    }
    
    struct Generic1Struct<T> {
        func generic1(name: String) {## do, whatever it needs with T ##}
    }
    
    func generic2<T>(name : String){
         Generic1Struct<T>().generic1(name: name)
    }