如何在 Swift 中显式特化一个泛型函数Cannot explicitly specialize a generic function

什么是显式专业化

显式特化是在调用点显式指定泛型函数类型的过程。

这是一个泛型函数的例子,它将创建一个 T 类型的数组,它要求 T 是 的子类UIView。

func viewFactory<T: UIView>(numberOfView: Int) -> [T] {
    return Array(repeating: T(), count: numberOfView)
}

如果我们想UIButton在viewFactory显式特化中产生一个out ,你必须像这样直接指定一个类型viewFactory

let buttons = viewFactory<UIButton>(numberOfView: 3)
// Cannot explicitly specialize a generic function

Swift [1]不支持显式特化太糟糕了,您将收到以下编译错误。

Cannot explicitly specialize a generic function

在开始解决方案之前,我认为了解如何确定泛型函数的类型参数是很好的

类型推断

泛型函数的类型参数总是通过类型推断确定的。要使函数可推断,它必须在其方法签名中引用类型参数。因此编译器可以从上下文推断类型参数。

您可以在方法参数中或作为返回类型引用类型参数。

在以下示例中,类型参数由 parameter(t: T)和 return type确定-> T。

func foo<T>(t: T)
func foo<T>() -> T

从方法的参数推断

这是一个从传递参数推断类型的泛型函数的更具体示例。

func greeeting<T: CustomStringConvertible>(_ t: T) {
    print(type(of: T.self))
    print("Hello, \(t.description)!")
}

greeeting("Sarunw")
// String.Type
//Hello, Sarunw!

greeeting(true)
// Bool.Type
// Hello, true!

该greeting函数接受符合CustomStringConvertible协议的任何类型 (T) 参数。我们将字符串和布尔值传递给函数,这就是T推断其类型的地方,Bool而String.

从返回类型推断

泛型函数推断其类型的另一种方式是通过返回类型。这方面的一个例子是我们在文章开头使用的那个。

func viewFactory<T: UIView>(numberOfView: Int) -> [T] {
    return Array(repeating: T(), count: numberOfView)
}

编译器可以从使用结果的上下文推断类型。这里有两个例子。

变量类型

存储函数结果的变量类型,用于确定泛型类型参数。

下面是一个示例,其中使用类型buttons来确定泛型类型。T将UIButton在这种情况下。

let buttons: [UIButton] = viewFactory(numberOfView: 3)

方法参数类型

如果将泛型函数结果作为任何方法的参数传递,则该方法的参数类型用于确定泛型类型。

下面是一个示例,其中methodThatsNeedButtons使用方法的参数类型来确定泛型类型。T也在UIButton这里。

func methodThatsNeedButtons(_ buttons: [UIButton]) {}

// 1
methodThatsNeedButtons(viewFactory(numberOfView: 3))

<1>viewFactory结果是用作一个参数methodThatsNeedButtons的方法,因此viewFactory可以推断出从方法参数类型的其类型methodThatsNeedButtons是[UIButton]。

# 解决方案
您可能需要使用显式特化的泛型函数是从返回类型推断其类型的函数 – 通过添加类型 T 的参数作为显式注入类型的方法来解决此问题。换句话说,我们让它从方法的参数中推断出来。让我们看看这个更改如何帮助我们直接指定参数的类型。

我修改了我们的viewFactory以支持这种明确的专业化。
“`
// 1
func viewFactory<T: UIView>(_ t: T.Type, numberOfView: Int) -> [T] {
return Array(repeating: T(), count: numberOfView)
}

// 2
viewFactory(UIButton.self, numberOfView: 3)
“`

<1> 我们添加一个类型为 的参数T.Type。这使得我们的泛型函数可以从传递的参数中推断出它的类型。
<2> 然后,我们可以T通过传递您希望此工厂创建的类型作为参数来显式指定类型。在这种情况下,一个按钮。

我们使用T.Type而不是T因为我们需要类型,而不是对象实例。

# 结论
Swift 不支持显式特化,但我们可以使用类型推断来实现类似的效果。Apple 在他们的 API 中也使用了这种技术。一个例子是decode(_:from:)。
“`
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable

let user = try? JSONDecoder().decode(User.self, from: dataJson)

“`

***
# 精品教程推荐
– [《CSDN SwiftUI源码大全》](https://www.openswiftui.com/?gr_redirect=csdn-swiftui%e6%ba%90%e7%a0%81%e5%a4%a7%e5%85%a8)

– [《小专栏 SwiftUI教程》](https://www.openswiftui.com/?gr_redirect=%e5%b0%8f%e4%b8%93%e6%a0%8f-swiftui%e6%95%99%e7%a8%8b)

***
# 加入我们一起学习SwiftUI
QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:[www.openswiftui.com](https://www.openswiftui.com)

发表回复