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

11

我有一个定义如下的枚举

enum Fruit {
    case Apple(associatedValue: String)
    case Orange(associatedValue: String)
}
我有一个函数,它接受一个 Fruit 类型的参数。
func printNameOnly(fruit: Fruit) {

}
在这个函数中,我想要将枚举值作为字符串获取,也就是说,我想要获取字符串“Apple”或“Orange”,而不用考虑相关的数值。在Swift中是否有可能做到这一点?
我可以编写一个函数,使用case语句获取水果枚举并返回一个字符串,但我正在尝试找到一种避免这样做的方法,因为我想要的字符串就是枚举案例名称本身。

你可以根据你的情况字符串添加额外的关联值。 - antonio081014
但是每次使用枚举时,我都必须指定一个字符串,例如:let v = .Apple("苹果") - Puneet
1
在Swift中,枚举的原始值和关联值不能共存。你可能想解释一下为什么要这样做,这可能会有另一种解决问题的方法。 - antonio081014
5个回答

20

尝试这个(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"

4

所以您想要一个带有原始值和相关值的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

我们可以在Swift中使用带有原始值和关联值的枚举,但如果这样做,我们需要小心,我在我的回答中尝试发现其中的问题。 - Paul B

1
如果您想为调试目的获取枚举案例标签,那么这个来自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版本中被破坏。

1

是的,反射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

0

当枚举类型具有关联值时,打印它们将列出所有的值以及枚举名称。例如:

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

这将产生:

Apple("myApple")

因此,要获取“Apple”,请提取到第一个“(”为止的部分。

4
我认为依赖于默认描述生成的字符串表示方式会显得很不专业。 - Puneet
也许是这样,但当您将所有枚举值转换为字符串时,就是这样做的。您依赖于“description”生成枚举名称。 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接