1

我正在尝试编写一个使用模板/泛型类型调度的库,但我无法弄清楚重载解析在 Swift 中是如何工作的。(有没有比The Swift Programming Language更多的技术参考?)

以下工作完全符合我的希望:

func f(_ v: String) { print(v) }
func f(_ v: String?) { f(v!) }
func f(_ v: Int) { print(v) }
func f(_ v: Int?) { f(v!) }
f("foo")
f(Optional("bar"))
f(2)
f(Optional(3))

这段代码也以同样的方式工作:

func g<T>(_ v: T) { print(v) }
func g<T>(_ v: T?) { g(v!) }
g("foo")
g(Optional("bar"))
g(2)
g(Optional(3))

但是当我编译这个时:

func h(_ v: String) { print(v) }
func h(_ v: Int) { print(v) }
func h<T>(_ v: T?) { h(v!) }
h("foo")
h(Optional("bar"))
h(2)
h(Optional(3))

我收到警告

all paths through this function will call itself
func h<T>(_ v: T?) { h(v!) }

果然,使用可选参数执行它会破坏堆栈。

我的第一个滑稽的理论是,也许泛型不参与非泛型的重载解决,但这是:

func i<T: StringProtocol>(_ v: T) { print(v) }
func i<T>(_ v: T?) { i(v!) }
i("foo")
i(Optional("bar"))

给了我同样的警告,第二次调用破坏了堆栈。

如果v是 type Optional(String),我什至不明白如何v!将其传递给期望 a 的泛型T?

4

2 回答 2

2

发生这种情况是因为在您的通用实现中不会发生任何类型推断。您可以通过执行一些可选的强制转换(以避免崩溃)并将其发送到正确的方法来解决这个问题,无论如何这实际上会自动发生。所以像:

func h<T>(_ v: T?) { 
  if let stringValue = v as? String {
    h(stringValue) 
  } else if let intValue = v as? Int {
    h(intValue) 
  }
}

也许有点违背了目的,但我可以告诉你,作为一名拥有多年经验的 Swift 开发人员,如果你的其余代码是编写的,这种泛型处理不会/不应该真正经常出现在实际应用程序中以一种 Swift 友好的方式。我想这有点基于意见,但确实如此。

至于这条评论:

如果 v 是 Optional(String) 类型,我什至不明白 v!可以传递给期望 T? 的泛型。

根据您的实现,您声明它v: T?,这意味着 v 必须是 typeT或者它是nil。因此v!,只有您(作为开发人员)保证 v 的类型为T,而不是nil,如果您错了,程序将崩溃。

我假设您这样做只是为了学习目的,但这是我在您的示例代码中注意到的最重要的事情 - 如果您要立即使用 ! 强制展开。

于 2020-12-17T22:25:57.813 回答
1

我希望更直接地回答泛型是如何工作的,但是 Swift 的协议和扩展为同一种调度提供了不同的方法。

protocol H { func h() }
extension String: H { func h() { print(self) } }
extension Int: H { func h() { print(self) } }
extension Optional: H where Wrapped: H { func h() { self!.h() } }
"foo".h()
Optional("bar").h()
2.h()
Optional(3).h()
Optional(Optional(3)).h()

不幸的是,据我所知,这种调度机制不能应用于元组(或函数类型),因为它们无法扩展。

于 2020-12-17T23:49:30.397 回答