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

nic*_*aef 90 enums swift

我试图将这个问题简化为最简单的形式,如下所示.

建立

Xcode版本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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和在另一个文件中初始化枚举的代码,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")
    }
}
Run Code Online (Sandbox Code Playgroud)

错误

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

Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Run Code Online (Sandbox Code Playgroud)

笔记

  1. 根据Swift语言指南:

    如果使用原始值类型定义枚举,则枚举会自动接收初始化程序,该初始化程序接受原始值类型的值(作为参数调用rawValue)并返回枚举成员或nil.

  2. 自定义初始值设定项MyEnum是在扩展中定义的,用于测试是否由于语言指南中的以下情况而删除了枚举的原始值初始值设定项.但是,它实现了相同的错误结果.

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

  3. 移动枚举定义以MyClass.swift解决错误,bar但不是foo.

  4. 删除自定义初始化程序可以解决这两个错误.

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

    init?(raw: Int) {
        self.init(rawValue: raw)
    }
    
    Run Code Online (Sandbox Code Playgroud)
  6. 明确声明协议符合RawRepresentableMyClass.swift解决用于内嵌错误bar,但会导致关于重复的符号链接错误的(因为原始值型隐式枚举符合RawRepresentable).

    extension MyEnum: RawRepresentable {}
    
    Run Code Online (Sandbox Code Playgroud)

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

alc*_*mla 24

这个错误在Xcode 7和Swift 2中得到了解决

  • 这种答案可以从相关票证的链接中获益,以便将来的访问者可以检查问题的状态. (20认同)

Ant*_*ine 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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


car*_*onr 6

你甚至可以使代码更简单,有用没有switch的情况下,这样你就不需要在添加新类型添加更多的情况.

enum VehicleType: Int, CustomStringConvertible {
    case car = 4
    case moped = 2
    case truck = 16
    case unknown = -1

    // MARK: - Helpers

    public var description: String {
        switch self {
        case .car: return "Car"
        case .truck: return "Truck"
        case .moped: return "Moped"
        case .unknown: return "unknown"
        }
    }

    static let all: [VehicleType] = [car, moped, truck]

    init?(rawDescription: String) {
        guard let type = VehicleType.all.first(where: { description == rawDescription })
            else { return nil }
        self = type
    }
}
Run Code Online (Sandbox Code Playgroud)