在我的项目中,我有几个枚举,我到处使用,这些枚举是基于外部json创建的,因此输入始终是可选的。如果无法从输入创建枚举,我将定义默认值。
我现在如何做事的例子:
package ...;
public class ListingMusic implements
RequestHandler<HashMap<String, Object>, String> {
@Override
public String handleRequest(HashMap<String, Object> input, Context context) {
...
}
}
这显然很有用,但我想让我的构造函数更加流畅,通用并适用于更多这些枚举。我的目标是实例化这样的枚举:
enum TextAlign:String {
case left, center, right
}
let rawData = [String:Any]()
func getTextAlign() -> TextAlign {
if let rawTextAlignString = rawData["textAlign"] as? String, let align = TextAlign(rawValue: rawTextAlignString) {
return align
}
return TextAlign.left
}
let textAlign = self.getTextAlign()
所以我基本上想要一个可用的初始化器,我可以为TextAlign枚举编写,但是必须有一种方法可以用更多的通用语言来声明它。方式,以便我可以在我的所有枚举:String实例上使用初始化程序。 我在swift中对泛型的语法和选项进行了一些改进。
有什么想法吗?
我看到很多答案都没有错,但可能我对我所寻找的内容不够清楚。
我有更多这样的枚举:
let textAlign = TextAlign(rawOptionalValue: rawData["textAlign"] as? String) ?? TextAlign.left
我想定义一个可以初始化所有这些枚举的函数。 (不是因为我懒惰,而是因为我想了解如何使用泛型)
我需要的是扩展中的一些静态函数,它适用于所有这些&#39; String / RawRepresentable&#39;枚举。我不想为每个枚举编写所有这些可用的初始值设定项。 (我相信它应该是可能的,但我无法弄清楚语法)
在与Joakim的回答中稍作后,我提出了以下解决方案:
enum TextAlign:String {
case left, center, right
}
enum CornerRadius:String {
case none, medium, large
}
enum Spacing:String {
case tight, medium, loose
}
这允许我使用此函数实例化extension RawRepresentable {
static func create<T:Any>(_ value: Any?, defaultValue: Self) -> Self where Self.RawValue == T {
guard let rawValue = value as? T, let instance = Self.init(rawValue: rawValue) else {
return defaultValue
}
return instance
}
}
和String
(及更多)类型的枚举。像这样:
Int
我喜欢我可以将enum TextAlign:String {
case left, center, right
}
enum CornerRadius:Int {
case none, medium, large
}
let json:[String:Any] = [
"textAlign":"left",
"cornerRadius":0
]
let cornerRadius = CornerRadius.create(json["cornerRadius"], defaultValue: .medium)
let align = TextAlign.create(json["textAlign"], defaultValue: .center)
作为参数传递,并通过Any?
来自行处理投射。
好吧,它的复杂性仍然让我感到困扰,所以我尝试了初始路线,imo看起来更干净了。现在整个事情看起来像这样:
let rawValue = value as? T
为方便起见,我创建了一个可用且不可用的init,其默认值为。
现在我可以像这样实例化任何枚举:
extension RawRepresentable {
init(from value: Any?, or defaultValue: Self) {
self = Self.init(from: value) ?? defaultValue
}
init?(from value: Any?) {
guard let rawValue = value as? Self.RawValue, let instance = Self.init(rawValue: rawValue) else {
return nil
}
self = instance
}
}
现在我完成了更新......
答案 0 :(得分:2)
这是一个可用于从字符串
创建枚举项的函数func createEnumItem<T: RawRepresentable>(_ value: String) -> T? where T.RawValue == String {
return T.init(rawValue: value)
}
然后像
一样使用它let textAlign: TextAlign = createEnumItem("right")!
let radius: CornerRadius = createEnumItem("medium")!
请注意,您始终在变量声明中包含枚举类型。
当然,因为返回值是可选的,所以你需要以比我的例子更好的方式处理它。
更新
如果你总是知道你的默认值是修改后的版本
func createEnumItem<T: RawRepresentable>(_ value: String, withDefault defaultItem: T) -> T where T.RawValue == String {
guard let item = T.init(rawValue: value) else {
return defaultItem
}
return item
}
答案 1 :(得分:1)
您可以声明这样的枚举
enum TextAlign: String {
case left, center, right
init(rawOptionalValue: String?) {
self = TextAlign(rawValue: rawOptionalValue ?? TextAlign.left.rawValue) ?? .left
}
}
然后像这样实例化它:
let textAlign = TextAlign(rawOptionalValue: rawData["textAlign"] as? String)
以下是一个默认值作为可选参数的示例:
enum TextAlign: String {
case left, center, right
init(rawOptionalValue: String?, defaultValue: TextAlign = TextAlign.left) {
self = TextAlign(rawValue: rawOptionalValue ?? defaultValue.rawValue) ?? defaultValue
}
}
let textAlign1 = TextAlign(rawOptionalValue: "left") // .left
let textAlign2 = TextAlign(rawOptionalValue: "right") // .right
let textAlign3 = TextAlign(rawOptionalValue: "center") // .center
let textAlign4 = TextAlign(rawOptionalValue: "notAnAlignment") // .left
let textAlign5 = TextAlign(rawOptionalValue: nil, defaultValue: .center) // .center
好的,现在我明白了。那么根据您的最新更新,您也可以这样做:
extension RawRepresentable {
init(rawOptionalValue: Any?, defaultValue: Self) {
guard let value = rawOptionalValue as? Self.RawValue else {
self = defaultValue
return
}
self = Self.init(rawValue: value) ?? defaultValue
}
}
与我之前的尝试相比,此处唯一的一点是您无法提供默认defaultValue
。所以你会这样使用它:
let textAlign1 = TextAlign(rawOptionalValue: "left", defaultValue: .left) // .left
let textAlign2 = TextAlign(rawOptionalValue: "right", defaultValue: .left) // .right
let textAlign3 = TextAlign(rawOptionalValue: "center", defaultValue: .left) // .center
let textAlign4 = TextAlign(rawOptionalValue: "notAnAlignment", defaultValue: .left) // .left
let textAlign5 = TextAlign(rawOptionalValue: nil, defaultValue: .center) // .center
答案 2 :(得分:1)
我认为你不需要新的功能。只需使用Optional.map(_:)
:
let alignment = rawData["textAlign"].map(TextAlign.init(rawValue:)) ?? .left
答案 3 :(得分:0)
你可以试试这个:
let textAlign = TextAlign(rawValue: rawData["textAlign"] as? String ?? TextAlign.left.rawValue)
答案 4 :(得分:0)
您可以像这样定义一个静态函数,并在代码中的任何位置使用它
enum TextAlign: String {
case left, center, right
static func getTextAlign(rawData: [String:Any]) -> TextAlign {
if let rawTextAlignString = rawData["textAlign"] as? String, let align = TextAlign(rawValue: rawTextAlignString) {
return align
}
return TextAlign.left
}
}
// Test
var myRawData = [String:Any]()
let textAlign1 = TextAlign.getTextAlign(rawData: myRawData) // left
myRawData["textAlign"] = "center"
let textAlign2 = TextAlign.getTextAlign(rawData: myRawData) // center