简体   繁体   English

使用关联值时获取枚举名称

[英]Get enumeration name when using associated values

I have an enum defined as follows 我的枚举定义如下

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

I have a function that takes an argument of type Fruit 我有一个函数,它接受类型为Fruit的参数

func printNameOnly(fruit: Fruit) {

}

In this function I want to get the enum case as a string, ie I want to get the string "Apple" or "Orange" without regard to whatever the associated value is. 在这个函数中,我想把枚举的情况作为一个字符串,即我想得到字符串“Apple”或“Orange”,而不考虑相关的值。 Is this possible with Swift? Swift可以实现吗?

I could obviously write a function which takes the fruit enum and returns a string using a case statement, but I am trying to find a way to avoid that since the string I want is the enum case name itself. 我显然可以编写一个函数,它接受水果枚举并使用case语句返回一个字符串,但我试图找到一种方法来避免这种情况,因为我想要的字符串是enum case name本身。

Try this (Swift 3.1). 试试这个(Swift 3.1)。 Covers associated or regular cases. 涵盖相关或常规案例。

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"

So you want a Swift enum with a RawValue and an associated value. 所以你想要一个带有RawValue 相关值的Swift枚举。

You can't 你不能

The best solution I can think of is adding a computed property to your enum (similarly to what you suggested in your own question). 我能想到的最好的解决方案是为你的枚举添加一个计算属性(类似于你在自己的问题中建议的那样)。

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

When enums have associated values, printing them will list all of the values along with the enum name. 当枚举具有关联值时,打印它们将列出所有值以及枚举名称。 For example: 例如:

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

This will produce: 这将产生:

Apple("myApple")

Therefore to get just "Apple", extract the part up to the first "(". 因此,要获得“Apple”,将部分提取到第一个“(”。

If you want to get the enumeration case label for debugging purposes, this neat private reflection function from the Swift runtime might come in handy: 如果你想获得枚举案例标签以进行调试,那么来自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>?

I've tested this approach with Swift 4 only. 我只用Swift 4测试了这种方法。 As mentioned above, I would not recommend using this for production code but rather only for debugging utilities as it is private/undocumented API and it might break in a future Swift version. 如上所述,我不建议将其用于生产代码,而是仅用于调试实用程序,因为它是私有/未记录的API,并且可能在将来的Swift版本中中断。

Yes, reflection API can help. 是的,反射API可以提供帮助。 This one will work both in debugging and in production. 这个可以在调试和生产中使用。

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

An extended version making use of both associated and raw values: 扩展版,利用相关 原始值的:

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