下面的代码片段演示了我要解决的问题。
import Foundation
protocol Printable {
func className() -> String
}
class SomeType: Printable {
func className() -> String {
return "SomeType"
}
}
class List<T> {
}
extension List where T: SomeType {
func className() -> String {
return "List<SomeType>"
}
}
func test(type: Any, message: String) {
guard type is Printable else {
print("\(message): ERROR")
return
}
print("\(message): SUCCESS")
}
let s: Any = SomeType()
test(type: s, message: "#1")
let slist1: Any = List<Any>()
test(type: slist1, message: "#2")
let slist2: Any = List<SomeType>()
test(type: slist2, message: "#3")
我怎样才能得到这个:
> #1: SUCCESS <--- as expected
> #2: ERROR <--- it's okay
> #3: SUCCESS <--- I am getting ERROR instead
似乎在此行中添加协议可以解决问题:
extension List: Printable where T: SomeType { // COMPILE ERROR
但不幸的是,这是不允许的。
另一种方法是使用:
extension List where T: Printable { // COMPILES OK in Swift 2.3 but doesn't work. COMPILE ERROR in Swift 3.0
但是,再次,没有运气通过测试。
我还可以将协议添加到受约束的泛型类型中吗?
答案 0 :(得分:1)
好吧,在你的警卫中,你问“这是否是可打印的,然后打印成功,否则打印错误”和你的第一个例子,你有一个可打印的SomeType。没关系。
之后你有slist1,类型为List<Any>
,它绝对不是可打印的类型,你会得到“错误”。那没关系
接下来你有List<SomeType>
。现在你有一个类扩展,将T定义为SomeType,对吗?但是你只是将T定义为SomeType而不是实际的 List ,所以当你将整个List传递给测试函数时,你不会让你的测试通过,因为List<AnyTypeHere>
不可打印,因为列表本身不实现Printable。
现在问题是,您想要整个列表是否可打印?如果是这样,那么只需使其符合SomeType或Printable协议即可。除了将单个List<SomeType>
元素传递给函数之外,这是唯一可以通过的方法。你的功能逻辑是正确的,但这只是对概念的误用。
因此,如果您希望List<SomeType>
进行该传递,那么您可以执行类似
class List<T> : Printable where T:SomeType {
//Add code here that conforms to protocol
}
这样做会使你的第二次测试失败,因为Any不会从SomeType继承,但它会让你的第三次测试通过,因为现在List<T>
是Printable而T也是SomeType类型。我的意思是,这只是一个真正快速的方式来获得你想要开始的东西。除非你添加额外的东西,否则你不会同时传递第二个和第三个测试,因为第二个测试是List类型为Any,而第三个测试是List类型为Printable。因此,其中任何一个都会抛出错误(因为List不是Printable类型)或者所有测试都显示成功(因为List类型为Printable)
答案 1 :(得分:1)
现在有了Swift 4.2,这是一个更新的答案,现在将条件一致性添加为功能。
在他们的spec on Github中,这种代码现已有效
extension List : Printable where T: SomeType {
func className() -> String {
return "List<SomeType>"
}
}