Is something like
是这样的
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
要么
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
可以在Swift 2.1中使用吗?
Update for Swift 4
Swift 4的更新
Swift 4 now support this feature! read more in here
Swift 4现在支持此功能!在这里阅读更多内容
2 个解决方案
#1
0
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
不是嵌套协议,但使用类型擦除器(“任何”结构)相当简单。
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray)
at the end of your function and it all just works. Lots of stdlib now returns Any
erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A
concrete, so it's much easier to work with.
实际上,返回值通常非常方便,因为调用者通常不太关心实际类型。你只需要在函数的末尾抛出一个AnyRandomAccessCollection(resultArray),它就可以了。很多stdlib现在返回任何橡皮擦。对于返回值问题,它几乎总是我推荐的方式。它具有制作混凝土的良好副作用,因此使用起来更容易。
If you want to keep the CollectionType
, then you need to restrict it at the point that you create a function that needs it. For example:
如果要保留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: +)
}
}
This isn't ideal, since it means you can have A
with the wrong kind of collection type. They just won't have a sum
method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
这并不理想,因为这意味着您可以使用错误类型的集合类型。他们只是没有总和方法。你也会发现自己在令人惊讶的地方重复了“IntCollection.Generator.Element == Int”。
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
根据我的经验,很少值得这样做,你很快就会回到Arrays(无论如何都是主导的CollectionType)。但是当你需要它时,这是两种主要的方法。这是我们今天最好的。
#2
0
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
你不能像在你的问题中那样直截了当,并且在SO上存在几个关于使用协议作为类型定义的主题,内容本身包含Self或相关类型要求(结果:这是不允许的)。参见例如Christik提供的链接,或使用关联类型和泛型的线程错误。
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
现在,对于上面的示例,您可以执行以下解决方法,但是,可能会模仿您正在寻找的行为
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
}
}
So you can implement blueprints for your generic collection types in you protocol A
, and implement these blueprints in the "interface type" B
, which also contain the actual collection as a member property. I have taken the largestValue()
method above from here.
因此,您可以在协议A中为通用集合类型实现蓝图,并在“接口类型”B中实现这些蓝图,其中还包含实际集合作为成员属性。我从这里采取了上面的maximumValue()方法。
Example usage:
用法示例:
/* 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
0
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
不是嵌套协议,但使用类型擦除器(“任何”结构)相当简单。
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray)
at the end of your function and it all just works. Lots of stdlib now returns Any
erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A
concrete, so it's much easier to work with.
实际上,返回值通常非常方便,因为调用者通常不太关心实际类型。你只需要在函数的末尾抛出一个AnyRandomAccessCollection(resultArray),它就可以了。很多stdlib现在返回任何橡皮擦。对于返回值问题,它几乎总是我推荐的方式。它具有制作混凝土的良好副作用,因此使用起来更容易。
If you want to keep the CollectionType
, then you need to restrict it at the point that you create a function that needs it. For example:
如果要保留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: +)
}
}
This isn't ideal, since it means you can have A
with the wrong kind of collection type. They just won't have a sum
method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
这并不理想,因为这意味着您可以使用错误类型的集合类型。他们只是没有总和方法。你也会发现自己在令人惊讶的地方重复了“IntCollection.Generator.Element == Int”。
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
根据我的经验,很少值得这样做,你很快就会回到Arrays(无论如何都是主导的CollectionType)。但是当你需要它时,这是两种主要的方法。这是我们今天最好的。
#2
0
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
你不能像在你的问题中那样直截了当,并且在SO上存在几个关于使用协议作为类型定义的主题,内容本身包含Self或相关类型要求(结果:这是不允许的)。参见例如Christik提供的链接,或使用关联类型和泛型的线程错误。
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
现在,对于上面的示例,您可以执行以下解决方法,但是,可能会模仿您正在寻找的行为
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
}
}
So you can implement blueprints for your generic collection types in you protocol A
, and implement these blueprints in the "interface type" B
, which also contain the actual collection as a member property. I have taken the largestValue()
method above from here.
因此,您可以在协议A中为通用集合类型实现蓝图,并在“接口类型”B中实现这些蓝图,其中还包含实际集合作为成员属性。我从这里采取了上面的maximumValue()方法。
Example usage:
用法示例:
/* 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