我正在尝试围绕Range
和ClosedRange
进行类型删除,但我被卡住了,因为他们有一些方法以Self
作为参数。
互联网上发现的所有类型的擦除样本都不涉及这种情况。
我想做一些不可能的事吗?
这是我的实施(简化):
protocol RangeType {
associatedtype _Bound: Comparable
func overlaps(_ other: Self) -> Bool
}
struct AnyRange<Bound: Comparable>: RangeType {
typealias _Bound = Bound
private let _overlaps: (AnyRange<Bound>) -> Bool
init<R: RangeType>(_ range: R) where R._Bound == Bound {
// Cannot assign value of type (R) -> Bool to type (AnyRange<...>) -> Bool
self._overlaps = range.overlaps
}
func overlaps(_ other: AnyRange<Bound>) -> Bool {
return _overlaps(other)
}
}
extension Range: RangeType {
typealias _Bound = Bound
}
extension ClosedRange: RangeType {
typealias _Bound = Bound
}
答案 0 :(得分:1)
在我提出该问题的解决方案之前,首先请注意,您尝试执行的操作可能未定义。协议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
的{{1}}方法和闭包(间接)在两个overlaps(_:)
实例之间进行比较。我们只需调用AnyRange
属性的_overlaps
属性,即可提供其他closure
实例和该实例的副本。使用一个副本来确保闭包可以使用AnyRange
而不必使用self
,因为编译器会抱怨“转义闭包捕获了self
参数的变体”(因此,{ {1}}有两种通用类型。
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
的结果指定类型。由于这两个原因,我们检查类型,然后检查它们是否重叠。