[英]Default value for Enum in Swift
我有一個enum
:
public enum PersonType:String {
case Cool = "cool"
case Nice = "rude"
case SoLazy = "so-lazy"
public var description: String {
switch self {
case .Cool:
return "Cool person"
case .Nice:
return "Nice person"
case .SoLazy:
return "its so lazy person"
}
}
public var typeImage: String {
switch self {
case .Cool:
return "cool.png"
case .Nice:
return "img_nice.png"
case .Solazy:
return "lazy.png"
}
}
}
問題我不知道所有的 person 類型鍵,所以我需要處理一個 person 類型的默認情況,並給它描述將是它的鍵,如“so-lazy”和默認圖像。
假設我從 Web 服務中得到了這個結果:
[
{
name: "john",
key: "cool"
},
{
name: "paul",
key: "funny"
}
]
我需要有一個默認情況來處理關鍵“有趣”
這是我在解析和創建 person 對象時初始化我的枚舉的方式:
if let personType = PersonType(rawValue:personTypeKey ?? "") {
self.personType = personType
}
我想要else
或更好的方法來處理枚舉中未知鍵的情況,並將鍵作為描述和默認圖像。
另一種適用於 Swift 3 的方法(可能是 2,不知道):
enum PersonType: String {
case cool = "cool"
case nice = "nice"
case soLazy = "so-lazy"
case other
}
let person = PersonType(rawValue: "funny") ?? .other
在這種情況下,person 變量的類型為 PersonType.other。
這樣做的缺點是您不知道 .other 案例的原始字符串值。
刪除原始類型,並使用帶有關聯值的enum
:
public enum PersonType {
case Cool
case Nice
case SoLazy
case Unknown(String)
static func parse(s:String) -> PersonType {
switch s {
case "Cool" : return .Cool
case "Nice" : return .Nice
case "SoLazy" : return .SoLazy
default: return Unknown(s)
}
}
}
刪除原始類型的缺點是您必須提供一些邏輯來解析已知的enum
值。 但是,好處是您可以將任何其他內容放入單個Unknown
案例中,同時保留實際的“未知”值以供以后使用。
這非常接近,但我希望能夠存儲可以與之關聯的值,就像使用 C 一樣。
enum Errors: Int {
case transactionNotFound = 500
case timeout = -1001
case invalidState = 409
case notFound = 404
case unknown
init(value: Int) {
if let error = Errors(rawValue: value) {
self = error
} else {
self = .unknown
}
}
}
Errors(value: 40) // .unknown
Errors(value: 409) // .invalidState
Errors(value: 500) // .transactionNotFound
必須創建一個自定義初始化程序,否則它是遞歸的。 並且仍然有可能意外地使用 rawValue 初始值設定項進行創建。
然而,這感覺更 Swifty,我刪除了: Int
類型說明符,它允許您使用關聯的值,現在我們不做任何特殊事情的特殊情況在other
處理:
enum Errors2 {
case transactionNotFound
case timeout
case invalidState
case notFound
case other(Int)
init(rawValue: Int) {
switch rawValue {
case 500:
self = .transactionNotFound
case -1001:
self = .timeout
case 409:
self = .invalidState
case 404:
self = .notFound
default:
self = .other(rawValue)
}
}
}
Errors2(rawValue: 40) // .other(40)
Errors2(rawValue: 409) // .invalidState
Errors2(rawValue: 500) // .transactionNotFound
Errors2(rawValue: -1001) // .timeout
有了這個,我可以獲得“其他”錯誤的實際值,並且我可以使用 rawValue 因此它的行為很像基於 Int 的枚舉。 有一個 case 語句來映射名稱,但從那時起您可以使用名稱而無需引用數字。
像這樣:
init() {
self = .Cool
}
在 Swift 5.1 中,現在可以設置默認值。 您的代碼如下所示:
enum PersonType {
case cool(String = "cool")
case nice(String = "rude")
case soLazy(String = "so-lazy")
}
這個問題現在已經很老了,而且在 Swift 世界中已經發生了很多變化。 使用 Swift 5 我會推薦下面的方法,它涉及為枚舉創建一個新的初始化程序:
public enum PersonType:String, ExpressibleByNilLiteral {
case Cool = "cool"
case Nice = "rude"
case SoLazy = "so-lazy"
public init(nilLiteral:()) {
self = .SoLazy
}
public init!(_ optionalValue:RawValue?) {
guard let rawValue = optionalValue,
let validValue = PersonType(rawValue:rawValue) else {
self = .SoLazy
return
}
self = validValue
}
public var description: String {
switch self {
case .Cool return "Cool Person"
//... etc
}
}
public var typeImage: String {
switch self {
case .Cool return "cool.png"
//... etc
}
}
}
像這樣使用它:
self.personType = PersonType(personTypeKey)
或者像這樣:
self.personType = nil
在任何一種情況下,即使該值對PersonType
枚舉無效或者它只是 nil,您也會獲得一個有效的枚舉,該枚舉設置為 .SoLazy 的默認值
這與該線程中的其他幾種方法類似,但它沒有列出所有可能的有效值(如果有很多可能會很笨拙),它使用多重guard let =
語句來保證它有效。
試試這個方法。
public enum PersonType:String {
case Cool = "cool"
case Nice = "rude"
case SoLazy = "so-lazy"
static let allKeys = [Cool.rawValue, Nice.rawValue, SoLazy.rawValue]
}
extension PersonType
{
func description(personTypeKey : String) -> String {
if PersonType.allKeys.contains(personTypeKey)
{
switch self {
case .Cool:
return "Cool person"
case .Nice:
return "Nice person"
case .SoLazy:
return "its so lazy person"
}
}
else
{
return "YourTextHere"
}
}
func typeImage(personTypeKey : String) -> String {
if PersonType.allKeys.contains(personTypeKey)
{
switch self {
case .Cool:
return "cool.png"
case .Nice:
return "img_nice.png"
case .SoLazy:
return "lazy.png"
}
}
else
{
return "YourImageHere"
}
}
}
對於你的情況:
Enum 的默認值:我只是添加了一個default
計算屬性,或者包含一個自定義的 init。
public enum PersonType:String {
case Cool = "cool"
case Nice = "rude"
case SoLazy = "so-lazy"
/// add a `default` computer property
public static var `default`: PersonType {
return .SoLazy
}
/// add an customize init function
public init(person: String? = nil) {
if let person = person {
switch person {
case "cool": self = .Cool
case "rude": self = .Nice
case "so-lazy": self = .SoLazy
default: self = .SoLazy
}
} else {
self = .SoLazy
}
}
public var description: String {
switch self {
case .Cool:
return "Cool person"
case .Nice:
return "Nice person"
case .SoLazy:
return "its so lazy person"
}
}
public var typeImage: String {
switch self {
case .Cool:
return "cool.png"
case .Nice:
return "img_nice.png"
case .SoLazy:
return "lazy.png"
}
}
}
使用:
if let personType = PersonType(rawValue:personTypeKey ?? "") {
self.personType = personType
} else {
self.personType = PersonType.default
}
或者
if let personType = PersonType(rawValue:personTypeKey ?? "") {
self.personType = personType
} else {
self.personType = PersonType()
}
帶有關聯值的枚舉的默認值:
public enum Gender {
case man
case woman
}
public enum PersonType {
case cool(Gender)
case nice(Gender)
case soLazy(Gender)
public static var `default`: PersonType {
return PersonType.make.soLazy()
}
public enum Builder {
public static func cool() -> PersonType {
return PersonType.cool(.woman)
}
public static func nice() -> PersonType {
return PersonType.nice(.woman)
}
public static func soLazy() -> PersonType {
return PersonType.soLazy(.woman)
}
}
public static var make: PersonType.Builder.Type {
return PersonType.Builder.self
}
public var description: String {
switch self {
case .cool(let gender):
switch gender {
case .man: return "Cool boy"
case .woman: return "Cool girl"
}
case .nice(let gender):
switch gender {
case .man: return "Nice boy"
case .woman: return "Nice girl"
}
case .soLazy(let gender):
switch gender {
case .man: return "its so lazy boy"
case .woman: return "its so lazy girl"
}
}
}
public var typeImage: String {
switch self {
case .cool(_):
return "cool.png"
case .nice(_):
return "img_nice.png"
case .soLazy(_):
return "lazy.png"
}
}
}
使用:
let onePersonType = PersonType.default
let anotherPersonType = PersonType.make.soLazy()
我在Ilya Puchka 的博客上找到了第二個案例解決方案。 並且在swift 的提案中也提到了這一點。
回答你的問題:
public enum PersonType:String {
case Cool = "cool"
case Nice = "rude"
case SoLazy = "so-lazy"
static var `default`: PersonType { return .SoLazy }
public init(rawValue: RawValue) {
switch rawValue {
case PersonType.Cool.rawValue: self = .Cool
case PersonType.Nice.rawValue: self = .Nice
case PersonType.SoLazy.rawValue: self = .SoLazy
default: self = .default
}
}
public var description: String {
switch self {
case .Cool:
return "Cool person"
case .Nice:
return "Nice person"
case .SoLazy:
return "its so lazy person"
}
}
public var typeImage: String {
switch self {
case .Cool:
return "cool.png"
case .Nice:
return "img_nice.png"
case .SoLazy:
return "lazy.png"
}
}
}
現在因為沒有帶有默認值的可失敗初始化器替換你的:
if let personType = PersonType(rawValue:personTypeKey ?? "") {
self.personType = personType
}
與:
personType = PersonType(rawValue: personTypeKey)
我建議使用這種方法
public enum Result {
case passed(hint: String)
case failed(message: String)
static let passed: Self = .passed(hint: "")
}
let res: Result = Result.passed
我想知道字典是否比 enum 更合適:
let dict = [
"Cool": "cool",
"Nice": "rude",
"SoLazy": "so-lazy"
]
let personType = "unknown"
let personDescription = dict[personType] ?? "Unknown"
更少的輸入,更快的處理,更自然的默認情況處理,更容易擴展。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.