【问题标题】:Switch statement for imported NS_OPTIONS (RawOptionSetType) in Swift?Swift中导入的NS_OPTIONS(RawOptionSetType)的切换语句?
【发布时间】:2014-10-12 19:52:19
【问题描述】:

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

让我们以 UIViewAutoresizing 为例。在 Objective-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
};

我可以像枚举一样在 Swift 中使用它:

let foo = UIViewAutoresizing([.FlexibleHeight, .FlexibleTopMargin])

是否可以使用 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")

}

【问题讨论】:

  • case let value where value & .FlexibleHeight != nil: 但还是不够好
  • if-else 语句对于如上所示的位掩码值没有多大意义,因为它会在第一个找到的非空位时停止,但一个变量会保留几个选项,并且用于几个非空位。
  • @vikingosegundo 你是对的。我想表达一些别的东西。查看更改。
  • 您的if 级联实际上并不是您说的if-else 级联,而是一系列独立条件。不过,这是一件好事,因为正如@vikingosegundo 所说,这种类型的值可以设置多个标志。在此处使用 switch 语句会造成伤害,但对您没有帮助 - 模式匹配仅适用于 互斥 选项。
  • 好吧,这不是最好的问题,但我们都是 swift 新手。在 switch 语句中,恰好执行了一个 case 语句。请参阅下面的答案以获取解决方案。

标签: swift switch-statement enumeration


【解决方案1】:

我昨天和今天尝试了几个小时来使用 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")
}

let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight

let usesFlexibleWidth = (foo & UIViewAutoresizing.FlexibleWidth) != nil;
let usesFlexibleHeight = (foo & UIViewAutoresizing.FlexibleHeight) != nil;

if usesFlexibleWidth {
    println("width")
}

if usesFlexibleHeight {
    println("height")
}

【讨论】:

    【解决方案2】:

    当然可以,尽管现在RawOptionSetType 没有实现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")
    }
    

    【讨论】:

    • 在第一场比赛中停止意味着它对于 NS_OPTIONS 来说是一个无用的解决方案。您将需要 fallthrough 关键字,或者您需要坚持使用多个 if
    【解决方案3】:

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

    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
        }
    }
    

    【讨论】:

    • 可能工作,但不是这样循环的优雅解决方案。我建议使用fallthrough 关键字寻求解决方案或坚持使用多个if
    【解决方案4】:

    我对这个问题感到非常沮丧,因此我编写了一个可以处理这些用例的Bitmask&lt;T&gt; 类。代码在 Github 上:brynbellomy/SwiftBitmask

    它允许你用任何类型的对象作为你的底层类型来做这样的事情(这里我使用enum):

    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 */ }
    

    ...您所要做的就是实现一个单一属性协议。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-22
      • 2011-06-22
      相关资源
      最近更新 更多