如何在 NSDate 中添加对 _Incrementable 的一致性
How to add conformance to _Incrementable in NSDate
我正在尝试在 NSDate
中添加对 ForwardIndexType
的一致性,以便我可以制作 Range<NSDate>
,为了做到这一点,我必须从 [ 实现 public func successor() -> Self
=15=].
我的实现非常简单,旨在说明在另一个日期之后的日期恰好在它之后的一秒,这不是这里要问的。
extension NSDate: ForwardIndexType {
public func successor() -> Self {
return NSDate(timeInterval: 1, sinceDate: self)
}
}
我得到的错误是
Cannot convert return expression of type 'NSDate
' to return type 'Self
'
我尝试添加 as Self
或 as! Self
但编译器不允许我添加,因为在这种情况下从 NSDate
转换为 Self
总是成功。将 Self
替换为 NSDate
也不起作用。
我怎样才能正确地做到这一点?
试试这个,将 Self
更改为 NSDate
,删除 ForwardIndexType
协议
extension NSDate: _Incrementable {
public func successor() -> Self {
return self.dynamicType.init(timeInterval: 1, sinceDate: self)
}
}
在类似代码中使用,
var date = NSDate()
date = date.successor()
let newDate = date.successor()
在ForwardIndexType
协议中,有advancedBy:
和distanceTo:
等方法,你实现方法successor
,只实现协议_Incrementable
。这会起作用。
正如一些评论所说,即使可能,您也不应该这样做。 NSDate
没有合乎逻辑的 "next." 发明一个有副作用的风险。 public 类型的扩展是全局的。如果你说 "the next date is the next second" 而另一个扩展说 "the next date is the next day?" 会发生什么?两者同样合理(同样不正确)。切勿添加可能会与其他人的不同含义发生冲突的扩展名。
你说你的目标是:
I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values
完全没问题。首先,正如您所说,您想要 "in a given interval." 优秀。那是 ClosedInterval<NSDate>
。为此,NSDate
必须是 Comparable。添加该扩展名没有错。任何合理实施的人都必须这样实施。
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
现在您想将其转换为整秒范围,而不是日期范围。然后打乱该范围内的元素,提取第一个 n
值,并将它们映射回日期。我们假设您已经拥有 Nate Cook 的 shuffle code.
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
// For convenience we're going to assume that the range is no larger than 68 years.
// If you need ranges larger than that, it's a bit more work and probably the subject
// of a second question. (See for the basis.)
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
let offsets = (0...intervalSize).shuffle()
return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval([=11=])) }.prefix(count))
}
您甚至可以将它与 ...
或 ..<
一起使用来定义您的间隔:
// 100 second-interval dates from the last hour
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100)
.forEach { print([=12=]) }
请注意,如果 n
明显小于间隔中的秒数,则此算法会有点慢并且会占用大量内存。我们必须创建一个可能非常庞大的数字数组,以便按照您的要求进行操作。如果你不关心重复,那一切就简单多了:
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
return (1...count).map { _ in
let offset = arc4random_uniform(intervalSize)
return interval.start.dateByAddingTimeInterval(Double(offset))
}
如果间隔明显大于 n
,则重复的可能性很低。如果您仍然想避免重复而不必分配那个巨大的初始数组,请考虑 Set
:
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
var offsets = Set<UInt32>()
while offsets.count < count {
offsets.insert(arc4random_uniform(intervalSize))
}
return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval([=14=])) }
}
a Set
的 trade-off 是如果 n
与间隔中的秒数大小相似,则此方法非常慢。在那种情况下,洗牌效率更高。
我正在尝试在 NSDate
中添加对 ForwardIndexType
的一致性,以便我可以制作 Range<NSDate>
,为了做到这一点,我必须从 [ 实现 public func successor() -> Self
=15=].
我的实现非常简单,旨在说明在另一个日期之后的日期恰好在它之后的一秒,这不是这里要问的。
extension NSDate: ForwardIndexType {
public func successor() -> Self {
return NSDate(timeInterval: 1, sinceDate: self)
}
}
我得到的错误是
Cannot convert return expression of type '
NSDate
' to return type 'Self
'
我尝试添加 as Self
或 as! Self
但编译器不允许我添加,因为在这种情况下从 NSDate
转换为 Self
总是成功。将 Self
替换为 NSDate
也不起作用。
我怎样才能正确地做到这一点?
试试这个,将 Self
更改为 NSDate
,删除 ForwardIndexType
协议
extension NSDate: _Incrementable {
public func successor() -> Self {
return self.dynamicType.init(timeInterval: 1, sinceDate: self)
}
}
在类似代码中使用,
var date = NSDate()
date = date.successor()
let newDate = date.successor()
在ForwardIndexType
协议中,有advancedBy:
和distanceTo:
等方法,你实现方法successor
,只实现协议_Incrementable
。这会起作用。
正如一些评论所说,即使可能,您也不应该这样做。 NSDate
没有合乎逻辑的 "next." 发明一个有副作用的风险。 public 类型的扩展是全局的。如果你说 "the next date is the next second" 而另一个扩展说 "the next date is the next day?" 会发生什么?两者同样合理(同样不正确)。切勿添加可能会与其他人的不同含义发生冲突的扩展名。
你说你的目标是:
I want to create a set of n random dates in a given interval. I wanted to shuffle a range and select the first n values
完全没问题。首先,正如您所说,您想要 "in a given interval." 优秀。那是 ClosedInterval<NSDate>
。为此,NSDate
必须是 Comparable。添加该扩展名没有错。任何合理实施的人都必须这样实施。
extension NSDate: Comparable {}
public func <(lhs: NSDate, rhs: NSDate) -> Bool {
return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
}
现在您想将其转换为整秒范围,而不是日期范围。然后打乱该范围内的元素,提取第一个 n
值,并将它们映射回日期。我们假设您已经拥有 Nate Cook 的 shuffle code.
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
// For convenience we're going to assume that the range is no larger than 68 years.
// If you need ranges larger than that, it's a bit more work and probably the subject
// of a second question. (See for the basis.)
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
let offsets = (0...intervalSize).shuffle()
return Array(offsets.map { interval.start.dateByAddingTimeInterval(NSTimeInterval([=11=])) }.prefix(count))
}
您甚至可以将它与 ...
或 ..<
一起使用来定义您的间隔:
// 100 second-interval dates from the last hour
randomDatesInInterval(NSDate(timeIntervalSinceNow: -3600)...NSDate(), count: 100)
.forEach { print([=12=]) }
请注意,如果 n
明显小于间隔中的秒数,则此算法会有点慢并且会占用大量内存。我们必须创建一个可能非常庞大的数字数组,以便按照您的要求进行操作。如果你不关心重复,那一切就简单多了:
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
return (1...count).map { _ in
let offset = arc4random_uniform(intervalSize)
return interval.start.dateByAddingTimeInterval(Double(offset))
}
如果间隔明显大于 n
,则重复的可能性很低。如果您仍然想避免重复而不必分配那个巨大的初始数组,请考虑 Set
:
func randomDatesInInterval<DateInterval: IntervalType where DateInterval.Bound == NSDate>
(interval: DateInterval, count: Int) -> [NSDate] {
let intervalSize = UInt32(interval.end.timeIntervalSinceDate(interval.start))
var offsets = Set<UInt32>()
while offsets.count < count {
offsets.insert(arc4random_uniform(intervalSize))
}
return offsets.sort().map { interval.start.dateByAddingTimeInterval(NSTimeInterval([=14=])) }
}
a Set
的 trade-off 是如果 n
与间隔中的秒数大小相似,则此方法非常慢。在那种情况下,洗牌效率更高。