So I have several enums looks like this:
enum TrackType: String, CustomStringConvertible {
case video
case audio
case subtitles
case unsupported
var description: String {
switch self {
case .video: return "视频"
case .audio: return "音轨"
case .subtitles: return "字幕"
case .unsupported: return "不支持的 track"
}
}
// custom initializater to provide default value
// so I don't have to write:
// "TrackType.init(rawValue: value) ?? .unsupported"
// everywhere
init(rawValue: String) {
switch rawValue {
case "video": self = .video
case "audio": self = .audio
case "subtitles": self = .subtitles
default: self = .unsupported
}
}
}
// usage
let value = "foobar"
let trackType = TrackType.init(rawValue: value) // .unsupported
The downside of this approach is I have to manually list all cases for every enum I write, so I go like this:
extension TrackType: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
guard let validValue = Self(rawValue: value) else {
self = .unsupported
return
}
self = validValue
}
}
// usage
let value = "foobar"
let trackType = value as TrackType // .unsupported
This way I could avoid the tedious listing work, but all of my enums have to conform to ExpressibleByStringLiteral, so it's still repetitive
I try to make a protocol like this:
protocol StringEnum: ExpressibleByStringLiteral {
static var `default`: Self { get }
init?(rawValue: String)
}
extension StringEnum {
init(stringLiteral value: String) {
guard let validValue = Self(rawValue: value) else {
self = Self.`default`
return
}
self = validValue
}
}
// error:
// Initializer 'init(stringLiteral:)' has different argument labels from those required by protocol 'StringEnum' ('init(rawValue:)')
enum TrackType: StringEnum {
static var `default` = TrackType.unsupported
case video
case audio
case subtitles
case unsupported
}
Where should I go from here?
I've seen answers in Default value for Enum in Swift, but none of them is convenient enough...