为什么我们不能将连续的rawValue设置为选项集?

时间:2018-02-02 12:07:40

标签: swift optionsettype

今天我尝试在Playground玩BitSet,我注意到这个模式

 struct Activities: OptionSet {
      let rawValue: Int
      static let eating = Activities(rawValue: 1)
      static let programming = Activities(rawValue: 2)
      static let breathing = Activities(rawValue: 3)
      static let saveGotham = Activities(rawValue: 4) 
}

 let act: Activities = [.eating, .programming, .saveGotham]

 act.contains(.breathing). //true /* this is unexpected */
 act.contains(.saveGotham) //true

虽然,阵列中没有包含值' .breathing'它仍然是真的。 我用不同的rawValue

修改了相同的结构
 struct Activities: OptionSet {
      let rawValue: Int
      static let eating = Activities(rawValue: 1)
      static let programming = Activities(rawValue: 8)
      static let breathing = Activities(rawValue: 16)
      static let saveGotham = Activities(rawValue: 32) 
}

 let act: Activities = [.eating, .programming, .saveGotham]

 act.contains(.breathing). //false
 act.contains(.saveGotham) //true

并获得所需的输出。如果有人能够解决这个问题并解释“选择套件”如何解决问题,那就太棒了。实际上是有效的。

谢谢。

2 个答案:

答案 0 :(得分:2)

OptionSet protocol意味着

  

...表示位集类型,其中各个位表示集合的成员。

在你的情况下,

let act: Activities = [.eating, .programming, .saveGotham]
print(act.rawValue) // 7

存储为包含原始值的BITWISE OR的整数 (1 | 2 | 4 = 7)

  act.contains(.breathing). //true /* this is unexpected */

测试BITWISE和7 & 3是否为非零(这种情况)。

因此,你不应该使用连续的原始值,而应该使用 两个,即每个互斥值由一个表示 位位置:

struct Activities: OptionSet {
    let rawValue: Int
    static let eating = Activities(rawValue: 1)
    static let programming = Activities(rawValue: 2)
    static let breathing = Activities(rawValue: 4)
    static let saveGotham = Activities(rawValue: 8)
}

或等效地:

struct Activities: OptionSet {
    let rawValue: Int
    static let eating = Activities(rawValue: 1 << 0)
    static let programming = Activities(rawValue: 1 << 1)
    static let breathing = Activities(rawValue: 1 << 2)
    static let saveGotham = Activities(rawValue: 1 << 3)
}

现在一切都按预期工作:

let act: Activities = [.eating, .programming, .saveGotham]
print(act.rawValue) // 11
print(act.contains(.breathing)) // false
print(act.contains(.saveGotham)) // true

答案 1 :(得分:1)

从OptionSet的文档页面

  

您使用OptionSet协议来表示位集类型,其中   各个位代表一组的成员。采用这个协议   您的自定义类型允许您执行与集相关的操作,例如   这些类型的成员资格测试,工会和交叉点。什么是   更多,当使用特定标准实施时,采用此方法   协议不需要你做额外的工作。

     

创建选项集时,请在类型中包含rawValue属性   宣言。 rawValue属性必须是符合的类型   FixedWidthInteger协议,例如Int或UInt8。接下来,创建   使用唯一的自定义类型的静态属性的唯一选项   每个人的权力为2(1,2,4,8,16等)   property的原始值,以便每个属性可以用a表示   单个类型的原始值。

rawValue应该是位设置类型。那么,上面的代码发生了什么,

让行为:活动= [.eating,.programming,.saveGotham]

因为吃1是相当于00000001,编程是2,即00000010,saveGotham是4,即00000100.所以,你的act变量现在将所有三位设置在最后,这可以表示为00000111。

00000111现在还包括呼吸。

从上面的注释中,您应该将原始值按位排列。

你可以从文档中拿一个例子,

struct ShippingOptions: OptionSet {
    let rawValue: Int

    static let nextDay    = ShippingOptions(rawValue: 1 << 0)
    static let secondDay  = ShippingOptions(rawValue: 1 << 1)
    static let priority   = ShippingOptions(rawValue: 1 << 2)
    static let standard   = ShippingOptions(rawValue: 1 << 3)

    static let express: ShippingOptions = [.nextDay, .secondDay]
    static let all: ShippingOptions = [.express, .priority, .standard]
}