gpt4 book ai didi

swift - OptionSetType 和枚举

转载 作者:IT王子 更新时间:2023-10-29 05:21:15 25 4
gpt4 key购买 nike

我有一个名为 ProgrammingLanguage 的枚举:

enum ProgrammingLanguage {
case Swift, Haskell, Scala
}

现在我有一个名为 Programmer 的类具有以下属性:
let favouriteLanguages: ProgrammingLanguage = .Swift

看到程序员如何拥有几种最喜欢的语言,我认为写这样的东西会很好:
let favouriteLanguages: ProgrammingLanguage = [.Swift, .Haskell]

经过一番研究,我意识到我需要符合 OptionSetType ,但这样做时,我提出了以下 3 个错误:

编程语言不符合
  • SetAlgebraType
  • OptionSetType
  • RawRepresentable

  • 当我看到 原始代表 错误,我立即想到了枚举的关联类型。无论如何,我希望能够打印枚举值,因此我将枚举签名更改为以下内容:
    case ProgrammingLanguage: String, OptionSetType {
    case Swift, Haskell, Scala
    }

    这使 2 个警告静音。但我仍然留下一个我不遵守协议(protocol)的问题 SetAlgebraType .

    经过一番反复试验,我发现枚举的关联类型为 Int修复它(这是有道理的,因为 RawRepresentable 协议(protocol)要求您实现签名 init(rawValue: Int) 的初始化程序)。但是,我对此并不满意;我希望能够轻松获得枚举的字符串表示。

    有人可以告诉我如何轻松做到这一点,以及为什么 OptionSetType需要一个 Int关联类型?

    编辑:

    以下声明编译正确,但在运行时出错:
    enum ProgrammingLanguage: Int, OptionSetType {
    case Swift, Scala, Haskell
    }

    extension ProgrammingLanguage {
    init(rawValue: Int) {
    self.init(rawValue: rawValue)
    }
    }

    let programmingLanguages: ProgrammingLanguage = [.Swift, .Scala]

    最佳答案

    编辑:我对我以前的自己当时没有提前说这件事感到惊讶,但是......而不是试图强制其他值类型进入 OptionSet协议(protocol)(Swift 3 从名称中删除了 Type),最好考虑使用这些类型的 API 并使用 Set在适当的情况下收集。
    OptionSet类型很奇怪。它们既是集合又不是集合——您可以从多个标志构造一个,但结果仍然是单个值。 (您可以做一些工作来找出与此类值等效的单个标志集合,但根据类型中可能的值,它可能不是唯一的。)

    另一方面,能够拥有一个东西,或者多个独特的东西,对于 API 的设计很重要。您希望用户说他们最喜欢的不止一个,还是强制要求只有一个?您想要允许多少个“收藏夹”?如果用户声称拥有多个收藏夹,是否应该按照用户特定的顺序对它们进行排名?这些都是OptionSet很难回答的问题。 -style 类型,但如果您使用 Set 则更容易类型或其他实际集合。

    这个答案的其余部分 a) 是旧的,使用 Swift 2 名称,并且 b) 假设您正在尝试实现 OptionSet无论如何,即使这对您的 API 来说是一个糟糕的选择...

    docs for OptionSetType :

    Supplies convenient conformance to SetAlgebraType for any type whose RawValue is a BitwiseOperationsType.



    换句话说,您可以声明 OptionSetType任何类型的一致性也采用 RawRepresentable .但是,当且仅当关联的原始值类型符合 ArrayLiteralConvertible 时,您才能获得神奇的集合代数语法支持(通过运算符和 BitwiseOperationsType 一致性)。 .

    因此,如果您的原始值类型是 String ,你运气不好——你没有获得集合代数的东西,因为 String不支持按位运算。 (这里的“有趣”之处,如果你能这么称呼的话,就是你可以扩展 String 来支持 BitwiseOperationsType ,如果你的实现满足 axioms ,你可以使用字符串作为选项集的原始值.)

    你在运行时的第二个语法错误是因为你创建了一个无限递归——调用 self.init(rawValue:)来自 init(rawValue:)一直锣直到它吹完堆栈。

    这可以说是一个错误( please file it ),您甚至可以在没有编译时错误的情况下尝试它。枚举不应该能够声明 OptionSetType一致性,因为:
  • 枚举的语义契约是它是一个闭集。通过声明您的 ProgrammingLanguage枚举您说的是 ProgrammingLanguage 类型的值必须是 Swift 之一, Scala , 或 Haskell ,而不是其他任何东西。 “Swift 和 Scala”的值不在该集合中。
  • OptionSetType的底层实现基于整数位域。 “Swift 和 Haskell”值( [.Swift, .Haskell] )实际上只是 .Swift.rawValue | .Haskell.rawValue .如果您的原始值集不是位对齐的,这会导致麻烦。也就是说,如果 .Swift.rawValue == 1 == 0b01 , 和 .Haskell.rawValue == 2 == 0b10 ,这些的按位或是 0b11 == 3 , 与 .Scala.rawValue 相同.

  • TLDR:如果你想要 OptionSetType一致性,声明一个结构。

    并使用 static let声明您的类型的成员。

    并选择您的原始值,以便您希望与其他成员的可能(按位或)组合不同的成员实际上是。
    struct ProgrammingLanguage: OptionSetType {
    let rawValue: Int

    // this initializer is required, but it's also automatically
    // synthesized if `rawValue` is the only member, so writing it
    // here is optional:
    init(rawValue: Int) { self.rawValue = rawValue }

    static let Swift = ProgrammingLanguage(rawValue: 0b001)
    static let Haskell = ProgrammingLanguage(rawValue: 0b010)
    static let Scala = ProgrammingLanguage(rawValue: 0b100)
    }

    使您的值保持不同的好方法:使用上述二进制文字语法,或使用位移 1 声明您的值,如下所示:
        static let Swift    = ProgrammingLanguage(rawValue: 1 << 0)
    static let Haskell = ProgrammingLanguage(rawValue: 1 << 1)
    static let Scala = ProgrammingLanguage(rawValue: 1 << 2)

    关于swift - OptionSetType 和枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36819163/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com