【问题标题】:Dynamically initialize enum based on associated value根据关联值动态初始化枚举
【发布时间】:2020-02-07 04:48:56
【问题描述】:

这是我的枚举:

enum E {
    case a(Int), b(String)
}

枚举的关联值类型是唯一的,并且始终是一个。

假设我有这个变量:

let myInt = 0

我想基于变量myInt动态地创建E 的实例。这应该会导致:

E.a(0)

但在“现实世界”中,我不知道我得到了什么属性。我只知道一件事:我可以用它初始化枚举E。我需要根据属性值动态初始化枚举。我目前在属性上有一个巨大的开关来初始化枚举,我不想要那个。

但我不知道如何完成这项任务。我尝试镜像枚举类型,但我得到了一个复杂类型,即使我知道类型,我也不知道如何继续初始化它。

所以我得到了某种类型的属性。我知道某些类型与枚举 E 中的一个 case 匹配,因为只有一种 case 的关联值对应于属性类型。我想用这种情况,用属性的值初始化那个枚举的一个实例。

【问题讨论】:

  • 我不清楚为什么你不能为每个案例编写一个初始化程序并让它构造相应的案例和相关值。
  • Swift 尚不具备执行此操作所需的反射功能。一些第三方库添加了这样的支持,但我什至不会打扰 tbh。只需使用switch
  • 是否涉及json或解码?
  • @MojtabaHosseini 不,在应用程序中,我们的操作与我提供的示例相同,但有更多案例
  • @JoshHomann 我不想编写不必要的/派生的 switch 语句/代码。有足够的信息来初始化枚举 IMO

标签: swift enums mirror


【解决方案1】:

您可以使用自定义初始化程序:(我使用了更具描述性的名称)

enum TypeFinder {
    case int(Int)
    case string(String)
    case unknown(Any)

    init(value: Any) {
        switch value {
        case let v as Int: self = .int(v)
        case let v as String: self = .string(v)
        default: self = .unknown(value)
        }
    }
}

测试:

var unknownTypeValue: Any = "Testing.."

print(TypeFinder(value: unknownTypeValue))

unknownTypeValue = 1234

print(TypeFinder(value: unknownTypeValue))

unknownTypeValue = true

print(TypeFinder(value: unknownTypeValue))

【讨论】:

  • 我在我的问题中说我想要动态(甚至加粗),我已经提到我现在有一个开关。
【解决方案2】:

如果您唯一的出发点是最终将成为关联值的类型,您可以使用switch 语句:

enum E {
    case a(Int)
    case b(String)

    init(associatedValue: Any) {
        switch associatedValue {
        case is Int:
            self = .a(associatedValue as! Int)
        case is String:
            self = .b(associatedValue as! String)
        default:
            fatalError("Unrecognized type!")
        }
    }
}

let response = E(associatedValue: 1) // .a(1)
let other = E(associatedValue: "haha!") // .b("haha!")

这里的问题是这个开关必须是详尽无遗的,意味着覆盖所有类型。所以你要么需要一个倾倒地箱 (.unreachable(Any)) 要么需要一个 fatalError,这样你就可以在开发中抓住它们。

【讨论】:

  • 我在我的问题中声明我希望它是动态的(甚至是粗体),我已经提到我现在有一个开关。
  • 您的意思是您希望编译器自动找出您拥有的内容。 a) 正如有人提到的那样,这在 Swift 中是不可能的,b) 即使是这样,它在 Swift 中也没有任何意义。您可以有两种情况,both 具有相同的关联值类型:case a(Int), case b(Int)。现在如果你得到一个Int,哪个是合适的?
  • 最后一句,如果保证每种类型只能使用一次,那就使用类型本身吧!通过“动态”将类型包装在仅描述类型的枚举中,您将一无所获。
  • '正如有人提到这在 Swift 中是不可能的'所以因为互联网上有人说某事是不可能的,事实是它不可能吗?我知道反射在 Java 中可以做什么,所以我想也许我可以在运行时动态地找到匹配的情况,而不是静态地输入开关。我一无所获?好吧,我希望我不会获得更多代码!我希望当我可以自己镜像案例时我会丢失代码。无论如何,谢谢你的努力。
  • 我对一无所获的评论是,如果你将你的类型包装在一个仅描述类型的枚举中,你仍然在编写一个 switch 语句,当你想要 unwrap 类型。所以你“动态地”创建一个枚举来避免写一个开关,但你仍然必须写一个开关,因为它是一个枚举。立即获取?
【解决方案3】:

我相信你可以做这样的事情

enum E: ExpressibleByStringLiteral, ExpressibleByIntegerLiteral {
    
    case a(Int), b(String)
    
    init(stringLiteral value: StringLiteralType) {
        self = .b(value)
    }
    
    init(integerLiteral value: IntegerLiteralType) {
        self = .a(value)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    • 2018-12-27
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多