SwiftにカスタムOptionSetType構造体があります。インスタンスのすべての値を列挙するにはどうすればよいですか?
これは私のOptionSetTypeです:
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)
}
私はこのようなものにしたいと思います:
let weekdays: WeekdaySet = [.Monday, .Tuesday]
for weekday in weekdays {
// Do something with weekday
}
Swift 4の時点で、OptionSetType
(Swift 2)またはOptionSet
(Swift 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)
Swift 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
}
}
}
}
以前の回答に基づいて、私は一般的なSwift 4ソリューションをIteratorProtocol
で作成しました:
_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
sが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
_
どうぞ。また、ボイラープレートの一部を削減するための便利な初期化子を追加しました。
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)
}