在我提出问题的解决方案之前,首先请注意,您尝试做的事情可能没有定义。协议RangeType 确保为类型与实现该功能的类型相同的实例定义overlaps(_:)。您试图通过模仿AnyIterator 的类型擦除无法以这种方式实现,因为虽然AnyRange 可以保证边界相同,但实际的底层类型本身可能不是(协议的要求)。
但是,这里解决了。如果您愿意,您可以添加一个特殊情况来处理两种不同类型之间的比较(尽管在这里完成对false 的评估可能是可取的)
protocol RangeType {
associatedtype _Bound: Comparable
func overlaps(_ other: Self) -> Bool
}
struct RangeComparison<Range, Element>: Equatable where Range: RangeType, Range._Bound == Element {
static func ==(lhs: RangeComparison<Range, Element>, rhs: RangeComparison<Range, Element>) -> Bool { lhs.range.overlaps(rhs.range) }
var range: Range
}
struct AnyRange<Bound: Comparable>: RangeType {
// MARK: RangeType
typealias _Bound = Bound
// Calls the closure of the `_overlaps` property which shields each type and allows self to be passed through
func overlaps(_ other: AnyRange<Bound>) -> Bool { _overlaps.closure(other, self) }
// Shielding structure. Allows us to compare to `AnyRange` instances
private struct OverlapContainer<A, B> {
private(set) var closure: (A, B) -> Bool
init(closure: @escaping (A, B) -> Bool) { self.closure = closure }
}
private var _overlaps: OverlapContainer<AnyRange<Bound>, Self>
// Holds reference to the actual range type. Note that if this is a class type, a strong reference will be created
private let range: Any
/**
Represents this particular type. Should not be called elsewhere in the structure as the cast would fail if `RT != R`
passed to the initiliazer
NOTE: `RT` as the generic type is used instead of `R` to keep us aware of this fact
*/
private nonmutating func rangeComparison<RT: RangeType>() -> RangeComparison<RT, Bound> { RangeComparison<RT, Bound>(range: range as! RT) }
init<R: RangeType>(_ range: R) where R._Bound == Bound {
self.range = range
self._overlaps = .init { other, this in
let thisComparison: RangeComparison<R, Bound> = this.rangeComparison()
// If the two types are the same, the comparison can be made
if type(of: other.range).self == R.self {
let otherComparison: RangeComparison<R, Bound> = other.rangeComparison()
return thisComparison == otherComparison
}
else { print("Not the same type"); return false } // Otherwise the comparison is invalid
}
}
}
extension Range: RangeType {
typealias _Bound = Bound
}
extension ClosedRange: RangeType {
typealias _Bound = Bound
}
// Examples
let range: Range<Int> = .init(5...8)
let rangeII: ClosedRange<Int> = 1...6
let any: AnyRange<Int> = .init(range)
let anyII: AnyRange<Int> = .init(rangeII)
print(any.overlaps(anyII)) // false.` Range` is not the same type as `ClosedRange`
let rangeIII: ClosedRange<Double> = 3.0...5.5
let rangeIV: ClosedRange<Double> = 1.0...4.0
let anyIII: AnyRange<Double> = .init(rangeIII)
let anyIV: AnyRange<Double> = .init(rangeIV)
print(anyIII.overlaps(anyIV)) // true. Both are 'ClosedRange<Double>' and actually overlap one another
这里有很多,所以让我解释一下每个部分
struct RangeComparison<Range, Element>: Equatable where Range: RangeType, Range._Bound == Element {
static func ==(lhs: RangeComparison<Range, Element>, rhs: RangeComparison<Range, Element>) -> Bool { lhs.range.overlaps(rhs.range) }
var range: Range
}
此结构用于表示给定的AnyRange 类型。正如我所提到的,如果两个RangeType 实例的类型不同,则不会定义它们的比较。这提供了一种媒介来确保这种情况,并便于通过此结构将两个 AnyRange 类型等同起来。
rangeComparison<RT: RangeType>() 方法使用传递给初始化器的RangeType (R) 的类型并将range 属性(设置为Any 并分配给传递给初始化器的实例)到此类型创建一个RangeComparison 实例。 range 属性保留了实际的底层类型。
private struct OverlapContainer<A, B> {
private(set) var closure: (A, B) -> Bool
init(closure: @escaping (A, B) -> Bool) { self.closure = closure }
}
private var _overlaps: OverlapContainer<AnyRange<Bound>, Self>
这个结构实际上允许我们(间接地)通过AnyRange 的overlaps(_:) 方法和闭包在两个AnyRange 实例之间进行比较。我们只需调用_overlaps 属性的closure 属性,提供另一个AnyRange 实例和该实例的副本。使用副本来确保闭包可以使用 self 而不必使用 self ,因为编译器会抱怨“转义闭包捕获变异 self 参数”(因此 OverlapContainer 有两种泛型类型)。
init<R: RangeType>(_ range: R) where R._Bound == Bound {
self.range = range
self._overlaps = .init { other, this in
let thisComparison: RangeComparison<R, Bound> = this.rangeComparison()
// If the two types are the same, the comparison can be made
if type(of: other.range).self == R.self {
let otherComparison: RangeComparison<R, Bound> = other.rangeComparison()
return thisComparison == otherComparison
}
else { print("Not the same type"); return false } // Otherwise the comparison is invalid
}
}
最后,我们检查两个比较是否具有相同的类型。如果您尝试将每个返回类型指定为 RangeComparison<R, Bound>,它将编译,但如果每个比较的 range 属性的类型与从泛型初始化程序推断的类型 R 不同,它将崩溃。您还“不能显式特化泛型函数”,因此必须为 rangeComparison() 的结果指定类型。由于这两个原因,我们先检查类型,然后检查它们是否重叠。