【问题标题】:How to require an enum be defined in Swift Protocol如何要求在 Swift 协议中定义枚举
【发布时间】:2016-05-20 18:26:46
【问题描述】:

是否可以让协议要求定义枚举?

//trying to do this
protocol JSONEncodable {
    enum PropertyName // Type not allowed here
    func valueForProperty(propertyName:PropertyName) -> Any
}

//which would be implemented like this
struct Person : JSONEncodable {
    var firstName : String
    var lastName : String

    enum PropertyName {
        case FirstName
        case LastName
        func allValues() {
            return [Person.PropertyName.FirstName, Person.PropertyName.LastName]
        }
        func stringValue() {
            return "\(self)"
        }
    }
    func valueForProperty(propertyName:PropertyName) -> Any {
        switch propertyName {

        case .FirstName:
            return firstName

        case .LastName:
            return lastName
        }
    }
}

//so that I could do something like this
extension JSONEncodable {

    func JSONObject() -> [String:AnyObject] {
        var dictionary = [String:AnyObject]()
        for propertyName in PropertyName.allValues {
            let value = valueForProperty(propertyName)

            if let valueObject = value as? AnyObject {
                dictionary[propertyName.stringValue()] = valueObject

            }else if let valueObject = value as? JSONEncodable {
                dictionary[propertyName.stringValue()] = valueObject.JSONObject()
            }

        }
        return dictionary
    }
}

【问题讨论】:

  • 你的用例是什么?
  • 你为什么要这个?你想达到什么目的?

标签: swift protocols


【解决方案1】:

协议可以有associatedtypes,这只是需要在任何子类中遵守:

enum MyEnum: String {
    case foo
    case bar
}

protocol RequiresEnum {
    associatedtype SomeEnumType: RawRepresentable where SomeEnumType.RawValue: StringProtocol

    func doSomethingWithEnum(someEnumType: SomeEnumType)
}

class MyRequiresEnum: RequiresEnum {
    typealias SomeEnumType = MyEnum

    func doSomethingWithEnum(someEnumType: SomeEnumType) {
        switch someEnumType {
        case .foo:
            print("foo")
        case .bar:
            print("bar")
        }
    }
}

let mre = MyRequiresEnum()
mre.doSomethingWithEnum(.bar)

编辑:associatedtype必须遵守

【讨论】:

  • 整洁,尽管没有什么迫使 SomeEnumType 实际上是 Enum 类型。虽然有效。
  • 我自己的问题解决方案与此类似,但这种方法将枚举的可访问性暴露给那些甚至不采用协议的控制器。我想知道枚举如何仅适用于采用协议。但是由于协议中不允许使用枚举,是否有另一种不使用枚举的方式来表示案例?
【解决方案2】:

我认为您可以使用遵循RawRepresentableassociatedtype 来做到这一点

这是一个例子:

protocol SomeProtocol {
    associatedtype SomeType: RawRepresentable
}

如果您需要指定RawRepresentable 的类型,例如String,您可以这样做:

protocol SomeProtocol {
    associatedtype SomeType: RawRepresentable where SomeType.RawValue: StringProtocol
}

现在,如果您尝试使用具有 StringRawRepresentableenum 以外的任何其他内容来实现协议,您将遇到编译器错误。 希望对你有帮助。

【讨论】:

    【解决方案3】:

    这在 Swift 中是不可能的。如果可能的话,目前还不清楚您将如何直接使用它,因为您无法参考任何案例(因为您不知道它们是什么)。您最终必须as 强制转换,这打破了协议的全部要点。 (如果enum 是一个集合类型,人们可能会想象它的用途,但它不是,如果是,你可以只需要“一个集合类型”。)

    【讨论】:

    • Rob Napier,如果这不可能,那么 Apple 如何在 Codable 协议中使用 CodingKeys 枚举?他的问题是不是类似于 Codable 协议?你的回答让我有点困惑。
    • 你不可能用 Swift 编写 Codable 协议。它需要编译器的特殊帮助。最终,我们希望 Swift 编译器足够强大,可以直接用该语言构建 Codable。
    猜你喜欢
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多