Dart 枚举原始值指定问题 及 原始值与枚举值转换问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dart 枚举原始值指定问题 及 原始值与枚举值转换问题相关的知识,希望对你有一定的参考价值。

参考技术A 最近在看尝试Flutter,在开发时打算用枚举标示5个常用的按键KeyCode,因为就值关系特定几个KeyCode,所以打算仅设定5个枚举值,并且指定其原始值为其int值。但是我发现没办法指定这个int值。

Dart语言的枚举不支持指定原始值,比如下面这种方式:

这样一来,如果想使枚举值有一个比较大的原始值,就只能使用本文件中KeyCode这种方式。一般如下:

但是如果我只想用Brown到Pink颜色这几种颜色,并且其原始值在100以上呢?比如键盘KeyCode☹️就有好多。

另外Dart语言枚举值到原始值的转换,直接取其index即可:

但却不支持从int原始值转换为枚举值,比如下面这种方式:

但enum提供了一个values属性,比如上面枚举有:

Color.values是一个有序数组,其下标和该位置的Color枚举值的原始值相等。
所以,如果一个枚举满足:1. 从零开始,2. 各个值密集排布,(Dart肯定满足,因为没办法指定原始值),
则可以通过下面方式实现原始值到枚举值的转换:

参考: https://news.dartlang.org/2013/04/enum-proposal-for-dart.html

Swift枚举使用String值获取Int Enum的值

【中文标题】Swift枚举使用String值获取Int Enum的值【英文标题】:Swift enum getting value of Int Enum using String value 【发布时间】:2019-09-04 12:53:30 【问题描述】:

我有一个原始值是 Int 的枚举。我知道如何获得原始价值。但是我正在通过 web 服务访问数据,并且 Enum 的数据以字符串值的形式出现。

让我给你看我的 Enum,然后我们将讨论需要转换为 Enum 的数据,然后获取原始值。

我的枚举:

enum ReportStatus : Int 
case None = 0
case Received = 2
case Forward = 9
case Reporting = 14
case Completed = 50

我从网络服务获得的数据正在向我发送价值 像这样的字符串

var valueToCompareWithEnum = "Forward"

我想要什么:

我想匹配那个字符串值并得到结果 int 值。 例如,当我收到“转发”时,我必须将其转换为枚举 并获得 9 Int 值。

我知道我可以为它制作开关盒,但我想知道它是否可以用更干净的方式处理.....

提前谢谢请帮忙。

【问题讨论】:

【参考方案1】:

您可以让您的枚举实现CaseIterable,然后使用Array.first(where:)将您的字符串与每个枚举案例的字符串表示进行比较

enum ReportStatus : Int, CaseIterable 
    case None = 0
    case Received = 2
    case Forward = 9
    case Reporting = 14
    case Completed = 50

    static func translate(_ string: String) -> Int? 
        return ReportStatus.allCases.first(where: string == "\($0)")?.rawValue
    


这里的变体是一个全局通用函数,它做同样的事情,但它返回枚举大小写而不是原始值。

func translate<T: CaseIterable>(_ string: String, forEnum: T.Type) -> T? 
    return forEnum.allCases.first(where: string == "\($0)")

用法

if let item = translate(valueToCompareWithEnum, forEnum: ReportStatus.self) 
    print(item.rawValue)

【讨论】:

【参考方案2】:

你可以这样编码;

enum ReportStatus : Int 
    case None = 0
    case Received = 2
    case Forward = 9
    case Reporting = 14
    case Completed = 50

    static func getRawValue(from value : String) -> Int 
        switch value 
        case "Forward":
            return self.Forward.rawValue
        case "Received":
            return self.Received.rawValue
        case "Reporting":
            return self.Reporting.rawValue
        case "Completed":
            return self.Completed.rawValue
        default:
            return self.None.rawValue
        
    




var valueToCompareWithEnum = "Forward"

let myVal = ReportStatus.getRawValue(from: valueToCompareWithEnum)

print(myVal) // 9

【讨论】:

除此之外没有干净的方法吗? @A.s.ALI 我猜.. 是的。 Apple 总是不赞成在方法中使用“get”这个词。 Swift 是否改变了这一点,或者它只适用于属性? @***foe 我总是在我的方法中使用 get (包括 obj-c 和 swift),而且我从来没有遇到过苹果方面的任何问题。如果您可以提供相关链接,那将更好地给您答案。我认为 Apple 在这一点上没有任何问题。 @dahiya_boy 它内置在 Objective-C 中,例如,如果您声明一个属性 @property (readonly) Thing* thing;,您可以通过提供 - (Thing*)thing ... 来实现它。这不适用于- (Thing*)getThing ... 。不过我不知道 Swift。【参考方案3】:

由于您是从服务器接收这些字符串,我假设您的意思是您正在接收以 JSON 编码的它们。如果是这样,那么您可能希望它们是可解码的。在这种情况下,您可以实现自定义解码器。

在我展示之前,我将重命名你的枚举 case 以匹配 Swift 风格,这是一个小写字母。我这样做是为了让问题稍微难一些,并展示更多你可以使用的技术。

enum ReportStatus : Int 
    case none = 0
    case received = 2
    case forward = 9
    case reporting = 14
    case completed = 50

这是最直接的方法:

extension ReportStatus: Decodable 
    init(from decoder: Decoder) throws 
        let container = try decoder.singleValueContainer()
        let stringValue = try container.decode(String.self)

        switch stringValue 
        case "None": self = .none
        case "Received": self = .received
        case "Forward": self = .forward
        case "Reporting": self = .reporting
        case "Completed": self = .completed
        default:
            throw DecodingError
                .valueNotFound(Self.self,
                               .init(codingPath: decoder.codingPath,
                                     debugDescription: "Unknown value for report status: \(stringValue)"))

        
    

这是一个非常好的技术,但由于我们的案例名称确实与服务器的密钥非常匹配(只是不完美),我们可以通过小写密钥来解决这个问题:

enum ReportStatus : Int, CaseIterable  // Note CaseIterable
    case none = 0
    case received = 2
    case forward = 9
    case reporting = 14
    case completed = 50


extension ReportStatus: Decodable 
    init(from decoder: Decoder) throws 
        let container = try decoder.singleValueContainer()
        let stringValue = try container.decode(String.self)

        guard let value = Self.allCases.first(where:  String(describing: $0) == stringValue.lowercased() )
            else  throw DecodingError
                .valueNotFound(Self.self,
                               .init(codingPath: decoder.codingPath,
                                     debugDescription: "Unknown value for report status: \(stringValue)"))
        
        self = value

    

【讨论】:

【参考方案4】:

我建议您将 Int enum 切换为 String 以使其更易于解析并添加一个字段以获取每种情况的 int 值:

enum ReportStatus: String 

    case none = "None"
    case received = "Received" 
    case forward = "Forward"
    case reporting = "Reporting"
    case completed = "Completed"

    var intValue: Int 
      switch self 
        case .none      : return 0 
        case .received  : return 2 
        case .forward   : return 9
        case .reporting : return 14
        case .completed : return 50
      
   



let valueToCompareWithEnum = "Forward"

if let myVal = ReportStatus(rawValue: valueToCompareWithEnum) 
    print(myVal.intValue) // 9

因为来自网络的数据是字符串格式,所以建议将其解析为字符串枚举大小写,然后在需要的地方使用您自己的 Int 值。

【讨论】:

以上是关于Dart 枚举原始值指定问题 及 原始值与枚举值转换问题的主要内容,如果未能解决你的问题,请参考以下文章

Swift学习笔记:枚举

带有浮点原始值的 Swift 枚举的“枚举大小写的原始值不是唯一的”

Swift:枚举编码如何获取原始值[重复]

在核心数据中保存没有原始值的快速枚举

Swift 3 - 如何使用枚举原始值作为 NSNotification.Name?

如何从Swift的原始值中获取枚举?