问题描述
给定一个具有两个泛型和多个类型约束初始化器的类型:
struct ComposableRequest <T,U> {
init() {
self.t = defaultT()
self.u = defaultU()
}
var t: T?
var u: U?
private func defaultT() -> T? {
nil
}
private func defaultT() -> T? where T == String {
"Test1"
}
private func defaultT() -> T? where T == Int {
1
}
private func defaultU() -> U? {
nil
}
private func defaultU() -> U? where U == String {
"Test2"
}
private func defaultU() -> U? where U == Int {
2
}
}
let first = ComposableRequest<String,Int>()
print(first.t) // I'd expect this to be `"Test1"`,but its nil!
print(first.u) // I'd expect this to be `2`,but its nil!
当多个类型约束选项都满足时,Swift 如何决定使用哪种类型约束方法?如果所选方法不明确,此代码是否应该编译?更专业的版本如何调用?
解决方法
此时的问题是,您正在做的事情几乎没有什么通用的东西了。正是出于这个原因,您可以轻松地获得之后的结果,而无需尝试使用 where
子句作为一种假重载:
struct MyGeneric<T,U> {
init() {
self.t = self.defaultT()
self.u = self.defaultU()
}
var t: T?
var u: U?
private func defaultT() -> T? {
if T.self is String.Type {
return Optional("Test" as! T)
}
if T.self is Int.Type {
return Optional(1 as! T)
}
return nil
}
private func defaultU() -> U? {
if U.self is String.Type {
return Optional("Test2" as! U)
}
if U.self is Int.Type {
return Optional(2 as! U)
}
return nil
}
}
,
在编译时静态选择重载。再加上结构体方法是静态分派的事实,意味着当编译器看到时,已经决定调用哪个defaultT
/defaultU
:
self.t = defaultT()
self.u = defaultU()
当这些行运行时不会。从编译器的角度来看,T
和 U
可以是任何类型,因此此处选择的最佳方法是返回 nil
的方法。
调用其他方法的一种方法是也约束初始化器:
init() where T == String,U == Int {
self.t = defaultT()
self.u = defaultU()
}
init() where T == Int,U == String {
self.t = defaultT()
self.u = defaultU()
}
init() where U == String {
self.t = defaultT()
self.u = defaultU()
}
init() where U == Int {
self.t = defaultT()
self.u = defaultU()
}
init() where T == String {
self.t = defaultT()
self.u = defaultU()
}
init() where T == Int {
self.t = defaultT()
self.u = defaultU()
}
init() {
self.t = defaultT()
self.u = defaultU()
}
但那是很多重复...每次您想添加对 String
和 Int
之外的新类型的支持时,您都需要添加更多的初始化程序...>
一种更好的方法是将 defaultX
方法移动到名为 HasDefault
的协议中:
protocol HasDefaults {
static func defaults() -> Self
}
extension String: HasDefaults {
static func defaults() -> [String] {
["Test1","Test2"]
}
}
extension Int: HasDefaults {
static func defaults() -> [Int] {
[1,2]
}
}
struct MyGeneric<T,U> {
init() {
t = nil
u = nil
}
init() where T: HasDefaults {
t = T.defaults()[0]
u = nil
}
init() where U: HasDefaults {
t = nil
u = U.defaults()[1]
}
init() where T: HasDefaults,U: HasDefaults {
t = T.defaults()[0]
u = U.defaults()[1]
}
var t: T?
var u: U?
}
您甚至可以选择不允许将任何非HasDefaults
类型用作 T
或 U
。这样你只需要一个初始化器。