Swift中的枚举和泛型
已编辑 你好,我想做我自己的单位转换器 但是,当我试图同时增加体重和长度时,出现了一些问题 有那么多重复的代码Swift中的枚举和泛型,swift,generics,enums,Swift,Generics,Enums,已编辑 你好,我想做我自己的单位转换器 但是,当我试图同时增加体重和长度时,出现了一些问题 有那么多重复的代码 enum LengthUnit: String{ case inch case cm case m case yard static func unit(of value: String) -> LengthUnit?{ switch value { case let value where value.c
enum LengthUnit: String{
case inch
case cm
case m
case yard
static func unit(of value: String) -> LengthUnit?{
switch value {
case let value where value.contains("inch"):
return .inch
case let value where value.contains("cm"):
return .cm
case let value where value.contains("m"):
return .m
case let value where value.contains("yard"):
return .yard
default:
return nil
}
}
}
enum WeightUnit:String {
case g
case kg
case lb
case oz
static func unit(of value: String) -> WeightUnit?{
switch value {
case let value where value.contains("g"):
return .g
case let value where value.contains("kg"):
return .kg
case let value where value.contains("lb"):
return .lb
case let value where value.contains("oz"):
return .oz
default:
return nil
}
}
}
不仅从String
函数中获取单位,而且还有许多用于转换的关联函数,其中存在重复的代码
enum LengthUnit: String{
case inch
case cm
case m
case yard
static func unit(of value: String) -> LengthUnit?{
switch value {
case let value where value.contains("inch"):
return .inch
case let value where value.contains("cm"):
return .cm
case let value where value.contains("m"):
return .m
case let value where value.contains("yard"):
return .yard
default:
return nil
}
}
}
enum WeightUnit:String {
case g
case kg
case lb
case oz
static func unit(of value: String) -> WeightUnit?{
switch value {
case let value where value.contains("g"):
return .g
case let value where value.contains("kg"):
return .kg
case let value where value.contains("lb"):
return .lb
case let value where value.contains("oz"):
return .oz
default:
return nil
}
}
}
所以我尝试用泛型来实现它,但我对此一无所知
如何将枚举和泛型用于这两种单元类型由于此处枚举项的原始值是枚举项的字符串版本,因此LengthUnit.inch-->“inch” 更新 包含删除字符串数字部分示例的更新版本。如果不知道需要什么样的数据,就很难知道最佳解决方案是什么
extension String {
var lengthUnit: LengthUnit? {
get {
let string = self.trimmingCharacters(in: CharacterSet(charactersIn: "01234567890."))
return LengthUnit(rawValue:string)
}
}
}
注释:由于您正在创建一个单位转换器,因此您需要在某个时刻将字符串拆分为值和单位,以便能够执行转换,因此首先使用我的原始版本可能更明智
注释2:我不知道如何在这里使用泛型,您的输入总是一个字符串,我认为让函数/属性返回泛型没有好处。您可以只使用一个
单元
枚举简化设计,然后只使用一个单元
属性而不是两个,因为您从字符串
继承了枚举,您将获得init?(rawValue:String)
免费解析初始值设定项。就我个人而言,我不会创建像unit(of:)
这样的函数,因为它只是丢掉了amount部分。相反,我将创建解析函数,如parse(value:String)->(Double,LengthUnit)
无论如何,如果您真的想要unit(of:)
函数,并希望尽可能减少代码重复,那么使用泛型确实会让您受益匪浅
首先,我们需要这样的Unit
marker协议
protocol UnitProtocol { }
然后,我们可以创建泛型函数,它将使用rawrrepresentable的init?(rawValue:String)
返回基于传递字符串的单位
func getUnit<U: UnitProtocol & RawRepresentable>(of value: String) -> U? where U.RawValue == String {
// you need better function to split amount and unit parts
// current allows expressions like "15.6.7.1cm"
// but that's question for another topic
let digitsAndDot = CharacterSet(charactersIn: "0123456789.")
let unitPart = String(value.drop(while: { digitsAndDot.contains($0.unicodeScalars.first!) }))
return U.init(rawValue: unitPart)
}
或者,在任何地方添加unit(of:)
方法,我们甚至可以做得更好并添加扩展
extension UnitProtocol where Self: RawRepresentable, Self.RawValue == String {
static func unit(of value: String) -> Self? {
return getUnit(of: value)
}
}
现在,只需将一致性添加到String
和unit
中,您就可以免费获得静态unit(of:)
enum WeightUnit: String, UnitProtocol {
case g
case kg
case lb
case oz
}
只要“单位案例名称”等于“单位字符串表示法”@DongkunLeeI编辑了我的问题代码。输入将是“15cm”或“15oz”我想消除重复的代码。您不能像在代码中那样使用contains
,因为例如15kg
将被转换为15weightUnit.g
,所以您需要在获取单位
属性之前或时将字符串拆分为值和单位。这就是我想要的!!谢谢
enum WeightUnit: String, UnitProtocol {
case g
case kg
case lb
case oz
}