我在Swift中有一个自定义的OptionSetType结构。如何枚举实例的所有值?
这是我的OptionSetType:
cp -p /from/libfoo.so /target/libfoo.so.tmp
mv -f /target/libfoo.so.tmp /target/libfoo.so
我想这样的事情:
struct WeekdaySet: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
static let Sunday = WeekdaySet(rawValue: 1 << 0)
static let Monday = WeekdaySet(rawValue: 1 << 1)
static let Tuesday = WeekdaySet(rawValue: 1 << 2)
static let Wednesday = WeekdaySet(rawValue: 1 << 3)
static let Thursday = WeekdaySet(rawValue: 1 << 4)
static let Friday = WeekdaySet(rawValue: 1 << 5)
static let Saturday = WeekdaySet(rawValue: 1 << 6)
}
答案 0 :(得分:39)
从Swift 4开始,标准库中没有方法
枚举OptionSetType
(Swift 2)的元素。
OptionSet
(斯威夫特3,4)。
这是一种可能的实现,它只是检查每个位
底层原始值,以及设置的每个位,
返回相应的元素。
“溢出乘法”&* 2
用作左移,因为<<
仅针对具体整数类型定义,但不针对IntegerType
协议定义。
Swift 2.2:
public extension OptionSetType where RawValue : IntegerType {
func elements() -> AnySequence<Self> {
var remainingBits = self.rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyGenerator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}
示例用法:
let weekdays: WeekdaySet = [.Monday, .Tuesday]
for weekday in weekdays.elements() {
print(weekday)
}
// Output:
// WeekdaySet(rawValue: 2)
// WeekdaySet(rawValue: 4)
斯威夫特3:
public extension OptionSet where RawValue : Integer {
func elements() -> AnySequence<Self> {
var remainingBits = rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyIterator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}
Swift 4:
public extension OptionSet where RawValue: FixedWidthInteger {
func elements() -> AnySequence<Self> {
var remainingBits = rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyIterator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}
答案 1 :(得分:9)
根据之前的答案,我使用IteratorProtocol
创建了一个通用的Swift 4解决方案:
public struct OptionSetIterator<Element: OptionSet>: IteratorProtocol where Element.RawValue == Int {
private let value: Element
public init(element: Element) {
self.value = element
}
private lazy var remainingBits = value.rawValue
private var bitMask = 1
public mutating func next() -> Element? {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Element(rawValue: bitMask)
}
}
return nil
}
}
比OptionSet扩展实现makeIterator()
假设您的OptionSet
为Int
:
extension OptionSet where Self.RawValue == Int {
public func makeIterator() -> OptionSetIterator<Self> {
return OptionSetIterator(element: self)
}
}
现在每次创建OptionSet时,只需将其符合Sequence
。
struct WeekdaySet: OptionSet, Sequence {
let rawValue: Int
...
}
您现在应该可以迭代它了:
let weekdays: WeekdaySet = [.monday, .tuesday]
for weekday in weekdays {
// Do something with weekday
}
我还创建了一个明确使用内容的类型:
typealias SequenceOptionSet = OptionSet & Sequence
答案 2 :(得分:1)
你走了。我还添加了一个便利初始化程序来减少一些样板:
enum Day: Int {
case Sun, Mon, Tue, Wed, Thu, Fri, Sat
}
struct WeekdaySet: OptionSetType {
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
init(_ rawValue: UInt8) {
self.init(rawValue: rawValue)
}
static let Sunday = WeekdaySet(1 << 0)
static let Monday = WeekdaySet(1 << 1)
static let Tuesday = WeekdaySet(1 << 2)
static let Wednesday = WeekdaySet(1 << 3)
static let Thursday = WeekdaySet(1 << 4)
static let Friday = WeekdaySet(1 << 5)
static let Saturday = WeekdaySet(1 << 6)
static let AllDays = [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
subscript(indexes: Day...) -> [WeekdaySet] {
var weekdaySets = [WeekdaySet]()
for i in indexes {
weekdaySets.append(WeekdaySet.AllDays[i.rawValue])
}
return weekdaySets
}
}
for weekday in WeekdaySet()[Day.Mon, Day.Tue] {
print(weekday)
}
答案 3 :(得分:0)
/// Day rawValues used in WeekdaySet. Day proper names capitalized.
enum Day: UInt8, CaseIterable {
case Sunday = 0b00000001
case Monday = 0b00000010
case Tuesday = 0b00000100
case Wednesday = 0b00001000
case Thursday = 0b00010000
case Friday = 0b00100000
case Saturday = 0b01000000
var description: String {
return "\(self)"
}
}
/// Seven days of the week represented with binary options.
struct WeekdaySet: OptionSet {
/// WeekdaySet initialized with Day (not with Weekday)
static let Sunday = WeekdaySet(.Sunday)
static let Monday = WeekdaySet(.Monday)
static let Tuesday = WeekdaySet(.Tuesday)
static let Wednesday = WeekdaySet(.Wednesday)
static let Thursday = WeekdaySet(.Thursday)
static let Friday = WeekdaySet(.Friday)
static let Saturday = WeekdaySet(.Saturday)
/// WeekdaySet initialized with Weekday (not with Day)
static let all: WeekdaySet = [.Sunday, .Monday, .Tuesday, .Wednesday, .Thursday, .Friday, .Saturday]
static let weekend: WeekdaySet = [.Saturday, .Sunday]
static let midweek: WeekdaySet = [.Tuesday, .Wednesday, .Thursday]
static let humpday: WeekdaySet = .Wednesday
/// OptionSet conformance
let rawValue: UInt8
init(rawValue: UInt8) {
self.rawValue = rawValue
}
/// Init using the enum Day
init (_ day: Day) {
self.rawValue = day.rawValue
}
}
extension WeekdaySet: CaseIterable {
static var allCases: [WeekdaySet] {
[
.Sunday,
.Monday,
.Tuesday,
.Wednesday,
.Thursday,
.Friday,
.Saturday,
]
}
/// Computed instance property to filter static allCases
var array: [WeekdaySet] {
get {
return WeekdaySet.allCases.filter { self.contains($0) }
}
}
}
extension WeekdaySet: Sequence {
typealias Iterator = AnyIterator<WeekdaySet>
func makeIterator() -> Iterator {
var iterator = array.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
extension WeekdaySet: CustomStringConvertible {
var description: String {
if self.array.count < 2 {
return Day(rawValue: self.rawValue)?.description ?? ""
}
var results: [String] = []
for weekday in self.array {
results.append(Day(rawValue: weekday.rawValue)?.description ?? "")
}
return String(describing: results)
}
}
/// A example set of weekdays
let customSet: WeekdaySet = [.Monday, .Tuesday]
/// Example usages:
print("Does the example set contain humpday?", customSet.contains(.humpday))
for weekday in customSet {
print("Is \(weekday) midweek?", WeekdaySet.midweek.contains(weekday))
}
print("Thursday:", WeekdaySet.Thursday)
print("Weekend names:", WeekdaySet.weekend)
print("All names", WeekdaySet.all)
// Printed results:
// Does the example set contain humpday? false
// Is Monday midweek? false
// Is Tuesday midweek? true
// Thursday: Thursday
// Weekend names: ["Sunday", "Saturday"]
// All names ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]