类似于
protocol A {
var intCollection: CollectionType<Int> { get }
}
或
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
可以在Swift 2.1中使用吗?
Swift 4的更新
Swift 4现在支持此功能! read more in here
答案 0 :(得分:0)
你不能像在你的问题中那样正确地做这个,并且在这里有关于使用协议作为类型定义的主题的若干线程,其内容本身包含Self或相关类型要求(结果:这是不允许)。参见例如link provided by Christik或帖子Error using associated types and generics。
现在,对于上面的示例,您可以执行以下解决方法,但是,可能会模仿您正在寻找的行为
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
因此,您可以在协议A
中为通用集合类型实现蓝图,并在&#34;接口类型&#34; B
中实现这些蓝图,其中还包含作为成员属性的实际集合。我已采用largestValue()
以上/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c
方法。
使用示例:
{{1}}
答案 1 :(得分:0)
不是嵌套协议,但使用类型擦除器(“任意”结构)相当简单。
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
这实际上对返回值来说通常非常方便,因为调用者通常不太关心实际类型。你只需要在函数结束时抛出一个return AnyRandomAccessCollection(resultArray)
,这一切都正常。很多stdlib现在返回Any
个橡皮擦。对于返回值问题,它几乎总是我推荐的方式。它具有使A
具体化的良好副作用,因此使用起来更容易。
如果要保留CollectionType
,则需要在创建需要它的函数时限制它。例如:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
这并不理想,因为这意味着您可以使用错误类型的集合类型A
。他们只是没有sum
方法。你也会发现自己在令人惊讶的地方重复“IntCollection.Generator.Element == Int”。
根据我的经验,很少值得这样做,你很快就会回到Arrays(无论如何都是主导的CollectionType)。但是当你需要它时,这是两个主要的方法。这是我们今天最好的。