我对以下代码有疑问:
func generic1<T>(name : String){
}
func generic2<T>(name : String){
generic1<T>(name)
}
该generic1(名称),结果编译器错误“无法明确专门的通用功能”
有什么办法可以避免这个错误?我无法更改generic1函数的签名,因此应为(String)-> Void
我对以下代码有疑问:
func generic1<T>(name : String){
}
func generic2<T>(name : String){
generic1<T>(name)
}
该generic1(名称),结果编译器错误“无法明确专门的通用功能”
有什么办法可以避免这个错误?我无法更改generic1函数的签名,因此应为(String)-> Void
T
都在使用generic1()
?您将如何调用该函数,以便编译器可以推断类型?
func foo<T>() -> T { ... }
使用t
类型T
为return 的对象做某事t
。明确专门T
将允许t1
在被infereed var t1 = foo<T>()
。我希望也可以通过这种方式调用函数。C#允许
Answers:
我也遇到了这个问题,我找到了解决此问题的方法。
在本文中,作者有同样的问题
https://www.iphonelife.com/blog/31369/swift-programming-101-generics-practical-guide
因此,问题似乎在于,编译器需要以某种方式推断T的类型。但是不允许简单地使用generic <type>(params ...)。
通常,编译器可以通过扫描参数类型来查找T的类型,因为在很多情况下都使用T。
就我而言,这有点不同,因为我函数的返回类型是T。就您而言,您似乎在函数中根本没有使用过T。我想您只是简化了示例代码。
所以我有以下功能
func getProperty<T>( propertyID : String ) -> T
而且例如
getProperty<Int>("countProperty")
编译器给我错误:
无法显式专门化泛型函数
因此,要给编译器提供另一种信息来源来推断T的类型,您必须显式声明要保存返回值的变量的类型。
var value : Int = getProperty("countProperty")
这样,编译器知道T必须是整数。
因此,我认为总体而言,这仅意味着如果您指定泛型函数,则必须至少在参数类型或返回类型中使用T。
func updateProperty<T>( propertyID : String )
let value = foo() as? Type
可以使用它,因此可以在中使用它,if
或者guard
结果是可选的,但它不能...
通常,有许多方法可以定义通用函数。但它们基于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
参考:
self.result = UIViewController.doSomething()
只要您在声明属性时就输入属性,我也可以自己实现作品。
doLastThing<UITextView>()
成为Swift doLastThing(UITextView.self)
,至少……这不是最糟糕的情况。比必须显式键入复杂的结果更好。感谢您的解决方法。
让编译器知道他正在处理什么类型,将类作为参数传递
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
})
由于您具有静态类型(作为参数的字符串),因此此处不需要泛型,但是如果要调用泛型函数,则可以执行以下操作。
使用通用方法
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")
我认为,当您指定泛型函数时,应指定一些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")
它会编译
到目前为止,我个人的最佳做法是使用@ orkhan-alikhanov的答案。如今,在查看SwiftUI以及实现方式.modifier()
和ViewModifier
实现方式时,我发现了另一种方式(或更有效的解决方法?)
只需将第二个函数包装到中struct
。
如果这给您“无法显式专门化泛型函数”
func generic2<T>(name: String){
generic1<T>(name)
}
这可能会有所帮助。将的声明包装generic1
为struct
:
struct Generic1Struct<T> {
func generic1(name: String) {## do, whatever it needs with T ##}
}
并调用:
func generic2<T>(name : String){
Generic1Struct<T>().generic1(name: name)
}
struct
是一个很好的示例。这里的解决方法没有更多信息-但可以通过编译器。信息相同,但结果不同?然后出了点问题。如果是编译器错误,则可以修复。我的通用类函数也有类似的问题class func retrieveByKey<T: GrandLite>(key: String) -> T?
。
我不能称其为let a = retrieveByKey<Categories>(key: "abc")
Categories是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")
给我一个错误时,它给了我一个错误,即即使Categories是GrandLite的子类,也无法将Categories.Type转换为GrandLite。然而...
class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T?
做工作,如果我试图let a = Categories.retrieveByKey(aType: [Categories](), key: "abc")
显然是一个子不工作的明确分配,但使用其他泛型类型(阵列)的隐式分配新建分配FY确实在斯威夫特3的工作。
aType
作为的实例T
,而不是将Categories
其自身放置。例如:let a = Categories.retrieveByKey(aType: Categories(), key: "abc")
。另一个解决方案是定义aType: T.Type
。然后将该方法称为let a = Categories.retrieveByKey(aType: Categories.self, key: "abc")