Swift中导入的NS_选项(RawOptionSetType)的开关语句?

Swift中导入的NS_选项(RawOptionSetType)的开关语句?,swift,switch-statement,enumeration,Swift,Switch Statement,Enumeration,Swift中的switch语句更具表现力。我想知道这是否可能: 例如,让我们看看UIViewAutoResize。目标C中对其定义如下: typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizin

Swift中的switch语句更具表现力。我想知道这是否可能:

例如,让我们看看UIViewAutoResize。目标C中对其定义如下:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
是否可以使用一个switch语句而不是多个if语句

if foo & UIViewAutoresizing.FlexibleHeight != nil {

}

if foo & UIViewAutoresizing.FlexibleWidth != nil {

}

if foo & UIViewAutoresizing.FlexibleTopMargin != nil {

}
类似于以下伪代码:

switch foo { // ** THIS IS PSEUDO CODE AND WILL NOT COMPILE **

case & .FlexibleHeight:
    println("height")

case & .FlexibleWidth:
    println("width")

case & .FlexibleTop:
    println("top")

}

我昨天和今天试了几个小时,想用switch来完成这项工作,但没有成功

原因是在这种特殊情况下,我们需要针对几个案例进行测试。在Swift中,我们需要使用
fallthrough
关键字。但是,如果下一种情况使用变量,我们不允许进入下一种情况,因为我们不能使用
case let where
语句,如下所示:

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
case let x where x & .FlexibleWidth != nil:
    println("width")
case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}
一旦案件触发,就会发生这种情况。但是

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
    fallthrough

case let x where x & .FlexibleWidth != nil:
    println("width")
    fallthrough

case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}
由于上述原因不起作用


我会用一个清晰的if语句,比如

let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight

let width = foo & UIViewAutoresizing.FlexibleWidth;
let height = foo & UIViewAutoresizing.FlexibleHeight;

if width == .FlexibleWidth {
    println("width")
}

if height == .FlexibleHeight {
    println("height")
}


当然可以,尽管现在
rawtoptionsetype
没有实现
BooleanType
协议有点复杂

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
case let x where x & .FlexibleWidth != nil:
    println("width")
case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}
请注意,这将在第一个匹配的条件下停止!所以这实际上是另一种形式:

if foo & .FlexibleHeight != nil {
    println("height")
} else if foo & .FlexibleWidth != nil {
    println("width")
} else if foo & .FlexibleTopMargin != nil {
    println("top margin")
}

我提出的另一个解决方案是:

let foo = /* .. your value to test .. */

let allCases = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleTopMargin]

for oneCase in allCases {
    switch oneCase & foo {

    case UIViewAutoresizing.FlexibleHeight:
        println("height")

    case UIViewAutoresizing.FlexibleWidth:
        println("width")

    case UIViewAutoresizing.FlexibleTopMargin:
        println("top")

    default:
        break
    }
}

我对这个问题感到非常沮丧,因此我编写了一个
位掩码
类来处理这些用例。代码在Github上:

它允许您使用任何类型的对象作为基础类型来执行类似的操作(这里我使用的是
enum
):

enum属性:IBitmask可表示,IAutoBitmaskable{
箱子大,丑,吓人
静态变量autobitmaskvalue:[MonsterAttributes]=[.Big、.ught、.thrable、]
var bitmaskValue:UInt16{return AutoBitmask..autobitmaskvalue for(self)}
init(bitmaskValue:UInt16){self=AutoBitmask.autovaluefromtmask(bitmaskValue)}
}
//初始化的各种方法
let选项:MonsterAttributes=.ught
让bitmaskOfOption=位掩码(选项)
让另一个bitmaskOfOption=| MonsterAttributes.ught//与bitmaskOfOption相同
设orWithVar=option |.Big/==Bitmask值为1 | 2的位掩码
设simpleOr=MonsterAttributes.Big |.ught/==Bitmask值为1 | 2的位掩码
//获取原始整数位掩码值
设simpleOrValue=simpleOr.bitmaskValue/==UInt16(1 | 2)
设orValue=(MonsterAttributes.Big |.丑陋)。bitmaskValue/==UInt16(1 | 2)
//实现布尔类型
如果simpleOr&.ught{/*此代码将执行*/}
//支持模式匹配操作符
如果simpleOr~=.ught{/*此代码将执行*/}
如果simpleOr~=(.ught |.trustry){/*此代码将执行*/}
。。。你所要做的就是实现一个单一属性的协议

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
case let x where x & .FlexibleWidth != nil:
    println("width")
case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}

我真的很好奇是否有人对代码有任何反馈或想法,所以如果你想到什么,请在队列中留下一个问题

案例let值,其中值和FlexibleHeight!=nil:但它仍然不好,
if else
语句对于上面所示的位屏蔽值没有多大意义,因为它将在第一个找到的非空位停止,但一个变量make会保留多个选项,并在那里保留多个非空位。@vikingosegundo您是对的。我想表达一些其他的东西。查看更改。您的
if
级联实际上并不像您所说的那样是
if
-
else
级联,而是一系列独立条件。不过,这是一件好事,因为正如@vikingosegundo所指出的,这种类型的值可以设置多个标志。在这里使用
switch
语句会对您造成伤害,但对您没有帮助-模式匹配仅适用于互斥选项。好吧,这不是最好的问题,但我们都是swift新手。在switch语句中,只执行一个case语句。请参阅下面我的答案,了解解决方案。在第一次匹配时停止意味着对于NS_选项来说这是一个无用的解决方案。您需要
故障排除
关键字,或者如果,您需要坚持使用多个
。可能会起作用,但这不是一个优雅的循环解决方案。我建议使用
故障排除
关键字寻求解决方案,或者如果
,则坚持使用多个
let foo = /* .. your value to test .. */

let allCases = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleTopMargin]

for oneCase in allCases {
    switch oneCase & foo {

    case UIViewAutoresizing.FlexibleHeight:
        println("height")

    case UIViewAutoresizing.FlexibleWidth:
        println("width")

    case UIViewAutoresizing.FlexibleTopMargin:
        println("top")

    default:
        break
    }
}
enum MonsterAttributes : IBitmaskRepresentable, IAutoBitmaskable {
    case Big, Ugly, Scary

    static var autoBitmaskValues : [MonsterAttributes] = [.Big, .Ugly, .Scary,]
    var  bitmaskValue: UInt16  { return AutoBitmask..autoBitmaskValueFor(self) }
    init(bitmaskValue: UInt16) { self = AutoBitmask.autoValueFromBitmask(bitmaskValue) }
}

// various ways to initialize
let option : MonsterAttributes = .Ugly

let bitmaskOfOption        = Bitmask(option)
let anotherBitmaskOfOption = |MonsterAttributes.Ugly // same as bitmaskOfOption

let orWithVar = option | .Big                 // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2
let simpleOr  = MonsterAttributes.Big | .Ugly // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2

// getting the raw integral bitmask value
let simpleOrValue = simpleOr.bitmaskValue                        // == UInt16(1 | 2)
let orValue       = (MonsterAttributes.Big | .Ugly).bitmaskValue // == UInt16(1 | 2)

// implements BooleanType
if simpleOr & .Ugly             { /* this code will execute */ }

// supports pattern matching operator
if simpleOr ~= .Ugly            { /* this code will execute */ }
if simpleOr ~= (.Ugly | .Scary) { /* this code will execute */ }