Swift中非文字值的枚举

Moh*_*sen 10 enums swift

有没有办法将像字典元组这样的非文字值映射到枚举?以下代码将抛出Raw value for enum must be literal.

enum FileType {
    case VIDEO = ["name": "Video", "contentTypeMatcher": "video/"]
    case IMAGE = ["name": "Image", "contentTypeMatcher": "image/"]
    case AUDIO = ["name": "Audio", "contentTypeMatcher": "aduio/"]
    case PDF   = ["name": "PDF", "contentTypeMatcher":"application/pdf"]
    case TEXT  = ["name": "Text", "contentTypeMatcher": "text/"]
    case FOLDER= ["name": "Folder", "contentTypeMatcher" :"application/x-directory"]
    case PLAIN = ["name": "Plain", "contentTypeMatcher": ""]
}
Run Code Online (Sandbox Code Playgroud)

当我使用元组时它是一样的:

enum FileType {
    case VIDEO  = (name: "Video", contentTypeMatcher: "video/")
    case IMAGE  = (name: "Image", contentTypeMatcher: "image/")
    case AUDIO  = (name: "Audio", contentTypeMatcher: "aduio/")
    case PDF    = (name: "PDF", contentTypeMatcher:"application/pdf")
    case TEXT   = (name: "Text", contentTypeMatcher: "text/")
    case FOLDER = (name: "Folder", contentTypeMatcher :"application/x-directory")
    case PLAIN  = (name: "Plain", contentTypeMatcher: "")
}
Run Code Online (Sandbox Code Playgroud)

Sta*_*ida 5

@Antonio 提供了解决方法,但没有回答实际问题。

定义你的枚举。

enum FileType {

    case Image, Video
}
Run Code Online (Sandbox Code Playgroud)

为 case 提供非文字值,无论您想要符合RawRepresentable协议的类型。通过枚举扩展来获得更清晰的代码。

extension FileType: RawRepresentable {

    typealias Tuple = (name: String, contentTypeMatcher: String)

    private static let allCases = [FileType.Image, .Video]

    // MARK: RawRepresentable

    typealias RawValue = Tuple

    init?(rawValue: Tuple) {

        guard let c = { () -> FileType? in

            for iCase in FileType.allCases {
                if rawValue == iCase.rawValue {
                    return iCase
                }
            }
            return nil

        }() else { return nil }
        self = c
    }

    var rawValue: Tuple {

        switch self {
        case .Image: return Tuple("Image", "image/")
        case .Video: return Tuple("Video", "video/")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为了能够Tuple在 switch 中匹配,实现模式匹配运算符。

private func ~= (lhs: FileType.Tuple, rhs: FileType.Tuple) -> Bool {

    return lhs.contentTypeMatcher == rhs.contentTypeMatcher && lhs.name == rhs.name
}
Run Code Online (Sandbox Code Playgroud)

就是这样...

let a = FileType.Image
print(a.rawValue.name) // "Image"
let b = FileType(rawValue: a.rawValue)!
print(a == b) // "true"
print(b.rawValue.contentTypeMatcher) // "image/"
Run Code Online (Sandbox Code Playgroud)

假设我没有质疑地回答了这个问题。现在......枚举(至少在 Swift 中)被设计为具有独特的案例。对此解决方法的警告是,您可以(我希望是偶然的)rawValue在更多情况下保持相同。一般来说,你的示例代码对我来说很奇怪。除非您(出于非常合理的原因)需要从元组创建新的枚举值,否则请考虑重新设计。如果您想采用这种解决方法,我建议(取决于项目)对所有 case 原始值是否唯一进行一些检查。如果没有,请考虑:

enum FileType {

    case Video, Image

    var name: String {
        switch self {
        case .Image: return "Image"
        case .Video: return "Video"
    }

    var contentTypeMatcher: String {
        switch self {
        case .Image: return "image/"
        case .Video: return "video/"
    }
}
Run Code Online (Sandbox Code Playgroud)


Ant*_*nio 4

语言参考在谈论枚举声明时明确指出:

原始值类型必须符合 Equatable 协议和以下文字可转换协议之一:IntegerLiteralConvertible(适用于整数文字)、FloatingPointLiteralConvertible(适用于浮点文字)、StringLiteralConvertible(适用于包含任意数量字符的字符串文字)以及 ExtendedGraphemeClusterLiteralConvertible(适用于包含任意数量字符的字符串文字)仅包含单个字符。

因此,除了文字之外,没有其他东西可以用作原始值。

一种可能的解决方法是将字典表示为字符串 - 例如,您可以使用逗号分隔元素,并使用冒号分隔键和值:

enum FileType : String {
    case VIDEO = "name:Video,contentTypeMatcher:video/"
    case IMAGE = "name:Image,contentTypeMatcher:image/"
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后,使用计算属性(或方法,如果您愿意)重建字典:

var dictValue: [String : String] {
    var dict = [String : String]()

    var elements = self.rawValue.componentsSeparatedByString(",")
    for element in elements {
        var parts = element.componentsSeparatedByString(":")
        if parts.count == 2 {
            dict[parts[0]] = parts[1]
        }
    }

    return dict
}
Run Code Online (Sandbox Code Playgroud)