如何解决如何在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
的枚举。请注意,我已经使其符合String
和CaseIterable
。
对于每种货币类型,我都分配一个String原始值。
例如,我创建了USD
案例。注意如何将所有数据放入1个字符串:"USD.US Dollar.2"
。我已经将每条信息分隔了一段时间。代号,名称和次要单位。如果要提取此数据,请使用raw
方法,它将返回(code:String,name:String,minorUnit: Int)
。
最后,我创建了一个新的初始化方法。它允许您根据其code
或name
初始化货币类型。如果我想赚取美元,您可以执行以下任一操作:
-
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
结构,就不需要泛型了。您所要做的就是给您的CurrencyType
和amount
。您的资金结构仍然是平等,可比和可哈希的。您甚至可以将钱四舍五入到最近的次要单位。
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 举报,一经查实,本站将立刻删除。