如何在Swift中通过字符串属性访问复杂的枚举项?

如何解决如何在Swift中通过字符串属性访问复杂的枚举项?

来自开源项目github.com/Flight-School/Money 货币声明如下:

Currency.swift

public protocol CurrencyType {
    /// The three letter ISO 4217 currency code.
    static var code: String { get }

    /// The name of the currency.
    static var name: String { get }

    static var minorUnit: Int { get }
}

public enum EUR: CurrencyType {
    public static var code: String {
        return "EUR"
    }

    public static var name: String {
        return "Euro"
    }

    public static var minorUnit: Int {
        return 2
    }
}

public enum GBP: CurrencyType {
    public static var code: String {
        return "GBP"
    }

    public static var name: String {
        return "Pound Sterling"
    }

    public static var minorUnit: Int {
        return 2
    }
}

public enum USD: CurrencyType {
    public static var code: String {
        return "USD"
    }

    public static var name: String {
        return "US Dollar"
    }

    public static var minorUnit: Int {
        return 2
    }
}
// ^^^More than 150 more like this in the file...

以及 Money.swift 中的Money结构,如下所示:

public struct Money<Currency: CurrencyType>: Equatable,Hashable {
    /// The amount of money.
    public var amount: Decimal

    /// Creates an amount of money with a given decimal number.
    public init(_ amount: Decimal) {
        self.amount = amount
    }

    /// The currency type.
    public var currency: CurrencyType.Type {
        return Currency.self
    }
    
    /**
        A monetary amount rounded to
        the number of places of the minor currency unit.
     */
    public var rounded: Money<Currency> {
        return Money<Currency>(amount.rounded(for: Currency.self))
    }
}

// MARK: - Comparable

extension Money: Comparable {
    public static func < (lhs: Money<Currency>,rhs: Money<Currency>) -> Bool {
        return lhs.amount < rhs.amount
    }
}

用法示例:

let amount = Decimal(12)
let monetaryAmount = Money<USD>(amount) // Works with any hard-coded currency code

我的问题代码:

我想要实现的是通过用户的字符串输入,使用用户选择的CurrencyType构造一个货币对象:

let userCurrencyCodeInput = "USD"
let userAmountInput = 39.95

let currency = CurrencyType(code: userCurrencyCodeInput ) // 'CurrencyType' cannot be constructed because it has no accessible initializers
let priceForUser = Money<currency>(userAmountInput) // Use of undeclared type 'currency'

我知道,为了获取相应的CurrencyType枚举项,我可以使用switch case语句,但是以上方法定义了150种以上的货币(这意味着我必须静态编写150种以上的案例),所以如果有一种将字符串代码映射到枚举项的code属性并访问它的动态方法,我最好学习和使用它,否则只需删除整个库并以更通用的方式重新开始实现。>

解决方法

不需要那么多枚举。我认为您正在寻找的是您是否可以基于CurrencyType输入从String接收数据。以下是试图大大减少代码大小和复杂性的尝试。


货币类型

在这里,我创建了一个名为CurrencyTypes的枚举。请注意,我已经使其符合StringCaseIterable

对于每种货币类型,我都分配一个String原始值。

例如,我创建了USD案例。注意如何将所有数据放入1个字符串:"USD.US Dollar.2"。我已经将每条信息分隔了一段时间。代号,名称和次要单位。如果要提取此数据,请使用raw方法,它将返回(code:String,name:String,minorUnit: Int)

最后,我创建了一个新的初始化方法。它允许您根据其codename初始化货币类型。如果我想赚取美元,您可以执行以下任一操作:

  • let currencyType = CurrencyType("USD")!
  • let currencyType = CurrencyType("US Dollar")!

这使我们可以轻松制作许多新的货币对象。如果要引入另一种货币,您要做的就是添加另一种情况(而不是创建一个新的枚举)。

enum CurrencyType: String,CaseIterable {
    case EUR = "EUR.Euro.2"
    case GBP = "GBP.Pound Sterling.2"
    case USD = "USD.US Dollar.2"
    // Add hundreds of cases based upon your liking
    
    /// Retrieve the **CODE**,**NAME**,and **MINOR UNIT** of a specified currency type
    var raw: (code: String,name: String,minorUnit: Int) {
        let values = self.rawValue.split(separator: ".").map { String($0) }
        return (values[0],values[1],Int(values[2])!)
    }

    /// Find currency based upon **CODE** or **NAME**
    init?(_ from: String) {
        for i in CurrencyType.allCases {
            let (code,name,_) = i.raw
            if code == from || name == from { self = i; return }
        }
        return nil
    }
}

如何省钱?

有了Money结构,就不需要泛型了。您所要做的就是给您的CurrencyTypeamount。您的资金结构仍然是平等,可比和可哈希的。您甚至可以将钱四舍五入到最近的次要单位。

struct Money: Equatable,Comparable,Hashable {
    var currency: CurrencyType,amount: Double
    init(_ currency: CurrencyType,_ amount: Double) { self.currency = currency; self.amount = amount }
    static func < (lhs: Money,rhs: Money) -> Bool { return lhs.amount < rhs.amount }
    public var rounded: Money {
        let roundTo = pow(10.0,Double(currency.raw.minorUnit))
        let roundedAmount = Double(Int(amount * roundTo)) / roundTo
        return Money(currency,roundedAmount)
    }
}

尝试一下!

// Example 1 - Currency Code
let userCurrencyCodeInput = "USD"
let userAmountInput = 39.951

if let findCurrency = CurrencyType("USD") {
    let currency = Money(findCurrency,userAmountInput)
    print(currency.rounded.amount) // prints 39.95
}

// Example 2 - Currency Name
let userCurrencyNameInput = "US Dollar"
if let findCurrency = CurrencyType("US Dollar") {
    let currency = Money(findCurrency,userAmountInput)
    print(currency.rounded.amount) // prints 39.95
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res