使用自定义初始值设定项的Swift枚举失去rawValue初始化程序

时间:2014-12-09 23:46:16

标签: swift enums

我试图将此问题归结为最简单的形式,如下所示。

设置

Xcode Version 6.1.1(6A2008a)

MyEnum.swift中定义的枚举:

internal enum MyEnum: Int {
    case Zero = 0, One, Two
}

extension MyEnum {
    init?(string: String) {
        switch string.lowercaseString {
        case "zero": self = .Zero
        case "one": self = .One
        case "two": self = .Two
        default: return nil
        }
    }
}

以及在另一个文件MyClass.swift中初始化枚举的代码:

internal class MyClass {
    let foo = MyEnum(rawValue: 0)  // Error
    let fooStr = MyEnum(string: "zero")

    func testFunc() {
        let bar = MyEnum(rawValue: 1)  // Error
        let barStr = MyEnum(string: "one")
    }
}

错误

尝试使用原始值初始化程序初始化MyEnum时,Xcode给出了以下错误:

Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'

备注

  1. the Swift Language Guide

      

    如果使用原始值类型定义枚举,则枚举会自动接收初始值设定项,该初始值设定项接受原始值类型的值(作为名为rawValue的参数)并返回枚举成员或{{ 1}}。

  2. nil的自定义初始化程序在扩展程序中定义,用于测试是否因为the Language Guide中的以下情况而删除了枚举的原始值初始值设定项。但是,它会产生相同的错误结果。

      

    请注意,如果为值类型定义自定义初始值设定项,则您将无法再访问该类型的默认初始值设定项(或成员初始值设定项,如果它是结构)。 [...]
      如果您希望使用默认初始化程序和成员初始化程序以及您自己的自定义初始化程序初始化您的自定义值类型,请在扩展名中编写自定义初始值设定项,而不是作为值类型的原始实现的一部分。

  3. 将枚举定义移至MyEnum可解决MyClass.swift的错误,但不会解决bar的错误。

  4. 删除自定义初始值设定项可解决这两个错误。

  5. 一种解决方法是在枚举定义中包含以下函数,并使用它代替提供的原始值初始值设定项。因此,似乎添加自定义初始值设定项与标记原始值初始值设定项foo具有类似的效果。

    private
  6. init?(raw: Int) { self.init(rawValue: raw) } 中明确声明与RawRepresentable的协议一致性解决了MyClass.swift的内联错误,但导致链接器出现重复符号错误(因为原始值类型枚举隐式符合bar)。

    RawRepresentable
  7. 任何人都可以更深入地了解这里发生了什么吗?为什么原始值初始化程序不可访问?

6 个答案:

答案 0 :(得分:23)

此错误在Xcode 7和Swift 2中解决

答案 1 :(得分:13)

extension TemplateSlotType {
    init?(rawString: String) {
        // Check if string contains 'carrousel'
        if rawString.rangeOfString("carrousel") != nil {
            self.init(rawValue:"carrousel")
        } else {
            self.init(rawValue:rawString)
        }
    }
}

在您的情况下,这将导致以下扩展名:

extension MyEnum {
    init?(string: String) {
        switch string.lowercaseString {
        case "zero": 
            self.init(rawValue:0)
        case "one": 
            self.init(rawValue:1)
        case "two":
            self.init(rawValue:2)
        default: 
            return nil
        }
    }
}

答案 2 :(得分:6)

如果没有GalenTestNgTestBase个案例,您甚至可以使代码更简单实用,这样您在添加新类型时就不需要添加更多案例。

switch

答案 3 :(得分:1)

Yeah this is an annoying issue. I'm currently working around it using a global-scope function that acts as a factory, i.e.

worldpopulationlist.add(map);

答案 4 :(得分:0)

这适用于Xcode 9.2上的Swift 4以及我的EnumSequence

enum Word: Int, EnumSequenceElement, CustomStringConvertible {
    case apple, cat, fun

    var description: String {
        switch self {
        case .apple:
            return "Apple"
        case .cat:
            return "Cat"
        case .fun:
            return "Fun"
        }
    }
}

let Words: [String: Word] = [
    "A": .apple,
    "C": .cat,
    "F": .fun
]

extension Word {
    var letter: String? {
        return Words.first(where: { (_, word) -> Bool in
            word == self
        })?.key
    }

    init?(_ letter: String) {
        if let word = Words[letter] {
            self = word
        } else {
            return nil
        }
    }
}

for word in EnumSequence<Word>() {
    if let letter = word.letter, let lhs = Word(letter), let rhs = Word(letter), lhs == rhs {
        print("\(letter) for \(word)")
    }
}

输出

A for Apple
C for Cat
F for Fun

答案 5 :(得分:-1)

将此添加到您的代码中:

extension MyEnum {
    init?(rawValue: Int) {
        switch rawValue {
        case 0: self = .Zero
        case 1: self = .One
        case 2: self = .Two
        default: return nil
        }
    }
}