我有一个名为ContentService的协议,旨在公开从各种REST API读取数据的常用功能。 ContentService的每个实现都将执行该特定API所需的机制。
protocol ContentService {
func loadNextPage<T>(pageStartId: T) -> [Datum]
//Other methods...
}
由于给定的API可能有不同的标记返回数据页边界的方式,我想在实现类中指定所需的类型,如下所示:
class ServiceA : ContentService {
func loadNextPage<Int>(pageStartId: Int) -> [Datum] {
//Do something with pageStartId typed as an Int
return posts
}
}
class ServiceB : ContentService {
func loadNextPage<NSDate>(pageStartId: NSDate) -> [Datum] {
//Do something with pageStartId typed as an NSDate
return posts
}
}
注意我在实现类型(ServiceA,ServiceB)的定义中指定了type参数,因为它们特定于该服务。我的期望是这些类的任何实例都有一个签名为loadNextPage(pageStartId: X) -> [Post]
的方法,其中X是实现该方法时为T提供的特定类型。
为了从api加载一页数据,我会使用这样的东西:
let apiA = ServiceA()
let apiB = ServiceB()
let dataA = apiA.loadNextPage(1234)
let dataB = apiB.loadNextPage(NSDate())
虽然这个编译没有错误。您还可以编译以下内容而不会出现错误:
let dataA = apiA.loadNextPage("Anything works here.")
因此,ServiceA的loadNextPage()方法不限于Int参数。此外,在loadNextPage()方法的方法定义中,虽然在Xcode中检查它时,pageStartId参数似乎是预期的类型,但我不能使用通常在该类型上可访问的任何运算符或方法。例如,在ServiceA的实现中,即使pageStartId应该是Int,我也无法let newId = pageStartId + 5
。
两个问题:
1)显然我对Swift中的泛型方法有些误解,并且想知道为什么不能使用这种模式。
2)如果有人有一个聪明的解决方案来实现我想要上面的尝试,我很想知道它。
答案 0 :(得分:4)
您的协议
protocol ContentService {
func loadNextPage<T>(pageStartId: T) -> [Datum]
//Other methods...
}
需要通用方法loadNextPage
和
func loadNextPage<Int>(pageStartId: Int) -> [Datum] {
//Do something with pageStartId typed as an Int
return posts
}
就是这样:占位符碰巧的通用方法
名字为Int
。在方法内部,Int
引用该占位符类型,隐藏全局Swift类型Int
。等价的定义是
func loadNextPage<FOO>(pageStartId: FOO) -> [Datum] {
//Do something with pageStartId typed as an Int
return posts
}
您可能想要的是使用关联类型 T
定义协议:
protocol ContentService {
associatedtype T
func loadNextPage(pageStartId: T) -> [Datum]
//Other methods...
}
和一个采用T == Int
协议的类:
class ServiceA : ContentService {
func loadNextPage(pageStartId: Int) -> [Datum] {
let newId = pageStartId + 5 // <-- This compiles now!
//Do something with pageStartId typed as an Int
return posts
}
}
现在
let dataA = apiA.loadNextPage(1234)
编译,但
let dataA2 = apiA.loadNextPage("Anything works here.")
// error: cannot convert value of type 'String' to expected argument type 'Int'
没有像预期的那样。