簡體   English   中英

使用關聯值時獲取枚舉名稱

[英]Get enumeration name when using associated values

我的枚舉定義如下

enum Fruit {
    case Apple(associatedValue: String)
    case Orange(associatedValue: String)
}

我有一個函數,它接受類型為Fruit的參數

func printNameOnly(fruit: Fruit) {

}

在這個函數中,我想把枚舉的情況作為一個字符串,即我想得到字符串“Apple”或“Orange”,而不考慮相關的值。 Swift可以實現嗎?

我顯然可以編寫一個函數,它接受水果枚舉並使用case語句返回一個字符串,但我試圖找到一種方法來避免這種情況,因為我想要的字符串是enum case name本身。

試試這個(Swift 3.1)。 涵蓋相關或常規案例。

enum Fruit {
    case banana
    case apple(String)
    case orange(String)

    var label:String {
        let mirror = Mirror(reflecting: self)
        if let label = mirror.children.first?.label {
            return label
        } else {
            return String(describing:self)
        }
    }
}

print(Fruit.banana.label) // "banana"
print(Fruit.apple("yum").label) // "apple"

所以你想要一個帶有RawValue 相關值的Swift枚舉。

你不能

我能想到的最好的解決方案是為你的枚舉添加一個計算屬性(類似於你在自己的問題中建議的那樣)。

enum Fruit {
    case Apple(name:String)
    case Orange(name:String)

    var fruitDesc: String {
        switch self {
        case .Apple: return "Apple"
        case .Orange: return "Orange"
        }
    }
}

let fruit = Fruit.Apple(name: "McIntosh")
print(fruit.fruitDesc) // Apple

當枚舉具有關聯值時,打印它們將列出所有值以及枚舉名稱。 例如:

let anApple = Fruit.Apple("myApple")
print(anApple)

這將產生:

Apple("myApple")

因此,要獲得“Apple”,將部分提取到第一個“(”。

如果你想獲得枚舉案例標簽以進行調試,那么來自Swift運行時的這個整潔的私有反射函數可能會派上用場:

/// Returns the case label for the given enumeration value.
public func getEnumCaseName<T>(_ value: T) -> String? {
    return __getEnumCaseName(value).flatMap { String(validatingUTF8: $0) }
}

/// A private Swift function from the compiler which returns the case
/// label of the given enumeration value, represented as a C string.
@_silgen_name("swift_EnumCaseName")
fileprivate func __getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?

我只用Swift 4測試了這種方法。 如上所述,我不建議將其用於生產代碼,而是僅用於調試實用程序,因為它是私有/未記錄的API,並且可能在將來的Swift版本中中斷。

是的,反射API可以提供幫助。 這個可以在調試和生產中使用。

enum Fruit {
    case apple(associatedValue: String)
    case orange(associatedValue: String)
}

func fruitNameOnly(fruit: Fruit) -> String {
    return Mirror(reflecting: fruit).children.first!.label!
}

let greenApple = Fruit.apple(associatedValue: "Green")

print(fruitNameOnly(fruit: greenApple)) // apple

擴展版,利用相關 原始值的:

enum Fruit: RawRepresentable {
    case apple(associatedValue: String)
    case orange(associatedValue: String)

   typealias RawValue = String
    var rawValue: String {

        //return Mirror(reflecting: self).children.first!.label!
        // we rather use a regular switch this time which allows for custom values
        switch self {
        case .apple:     return "apple"
        case .orange(let av):   return "orange " + av // Edge case, careful!
        // Normally rawValues should form one to one relationship.
        // RawRepresentable protocol indicates, that you can "switch back and forth between a custom type and an associated RawValue type without losing the value of the original RawRepresentable type" (developer.apple.com/documentation/swift/rawrepresentable)

        }
    }

    init?(rawValue: String) {
        switch rawValue {
        case "apple":
            self = .apple(associatedValue: "")
        case "orange":
            self = .orange(associatedValue: "")
        default:
            return nil
        }
    }
}

func fruitNameOnly(fruit: Fruit) -> String {
    return Mirror(reflecting: fruit).children.first!.label!
}

let greenApple = Fruit.apple(associatedValue: "green")
print(fruitNameOnly(fruit: greenApple)) // apple

if let yellowOrange = Fruit.init(rawValue: "orange") {
   print(yellowOrange) // orange(associatedValue: "")
}
print(greenApple.rawValue) //apple
let redOrange = Fruit.orange(associatedValue: "red")
print(redOrange.rawValue) //orange red

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM