不太确定如何为此标出一个好的标题...
我想定义一个通用协议GBucket
,它有点像一组相同类型的项目。有点像CollectionType
,但功能却少得多。像这样:
public protocol GBucket {
associatedtype BElement
func splitBucket
<A: GBucket, B: GBucket where A.BElement == Self.BElement,
B.BElement == Self.BElement>
(idx: Int) -> ( A, B )
}
它基本上只提供了一种将GBucket
拆分为两个新GBucket
的方法。它可以是符合协议的任何类型 - 即返回的部分不必是进行拆分的同一类。
我尝试将其作为示例实现:
extension ArraySlice : GBucket {
public typealias BElement = Generator.Element
public func splitBucket
<A: GBucket, B: GBucket where A.BElement == BElement,
B.BElement == BElement>
(idx: Int) -> ( A, B )
{
let ls : ArraySlice<A.BElement> = self[0..<idx]
let a : A = ls // this conversion FAILs
return ( a, self[idx..<self.count] ) // this too, of course ;-)
}
}
这会产生:
无法转换'ArraySlice&lt;类型的值元素&gt;'指定类型'A'
据我所知,转换就好了。 ArraySlice
是GBucket
,由于where
规范,元素类型相同。
另一个较短的示例说明了不使用数组内容的问题:
public protocol GBucket {
associatedtype BElement
func otherBucket<A: GBucket where A.BElement == Self.BElement>() -> A
}
public class MyBucketType<T> : GBucket {
public typealias BElement = T
public func otherBucket<A: GBucket where A.BElement == BElement>() -> A {
return MyBucketType<A.BElement>()
}
}
我做错了什么?
答案 0 :(得分:0)
Rasmus在评论中发布了一个正确的链接,很好地解释了为什么问题中的方法失败了:Swift Types - Returning constrained generics from functions and methods。他没有修改他的答案,因此我提供了一个 - 这真的是他的; - )
关键是在呼叫站点处解决了泛型问题。通用部分实际上更像是C宏。从概念上讲,它没有任何动态 - 它实际上是一个&#34;用实际类型替换一些泛型类型&#34;。
看看这个:
extension ArraySlice : GBucket {
public typealias BElement = Generator.Element
public func splitBucket
<A: GBucket, B: GBucket where A.BElement == BElement,
B.BElement == BElement>
(idx: Int) -> ( A, B )
{
let ls : ArraySlice<A.BElement> = self[0..<idx]
let a : A = ls // this conversion FAILs
return ( a, self[idx..<self.count] ) // this too, of course ;-)
}
}
仅当调用splitBucket
方法(或通过其他方式专门化)时,类型A和B才会被替换为类型!例如:
let aSlice : ArraySlice<Int> = myArray[1..<5]
let result : ( Array<Int>, Array<Int> ) = aSlice.splitBucket(3)
A
中的B
和splitBucket
类型只会在此时扩展为Array<Int>
。 I.E.该函数的专用(泛型扩展)版本将是:
public func splitBucket(idx: Int) -> ( Array<Int>, Array<Int> ) {
let ls : ArraySlice<A.BElement> = self[0..<idx]
let a : Array<Int> = ls // this conversion FAILs
return ( a, self[idx..<self.count] ) // this too, of course ;-)
}
这就是let a
必须失败的原因。
P.S。:这并没有回答如何实现目标,但这是一个起点: - )
答案 1 :(得分:-1)
ArraySlice符合GBucket,A符合GBucket并不意味着你可以在它们之间进行转换。您可以从更专业的类型转换为更常规的类型,但不能在两种不同的更专用的类型之间转换。
也许下面的代码可以解决您的问题?
public protocol GBucket : CollectionType {
func splitBucket(idx: Int) -> ( Self, Self )
}
extension ArraySlice : GBucket {
public func splitBucket(idx: Int) -> ( ArraySlice, ArraySlice )
{
let A = self[0..<idx]
let B = self[idx..<self.count]
return (A, B)
}
}