web-dev-qa-db-ja.com

enumをSwift Protocolで定義することを要求する方法

列挙型を定義することをプロトコルに要求させることは可能ですか?

//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
    }
}
16
joels

これはSwiftでは不可能です。可能である場合は、どのケースを参照することができないので(どのケースなのかわからないため)、それを直接使用する方法は不明です。最終的にはasキャストする必要がありますが、これはプロトコルの全体のポイントを壊します。 (enumがコレクション型である場合の使用を想像するかもしれませんが、そうではなく、それが「コレクション型」を必要とするだけである可能性があります。)

7
Rob Napier

プロトコルはassociatedtypesを持つことができます。これは、任意のサブクラスで順守する必要があるだけです。

enum MyEnum {
    case foo
    case bar
}

protocol RequiresEnum {
    associatedtype SomeEnumType

    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必須に準拠する

18
Mackarous

associatedtypeに準拠しているRawRepresentableを使用してそれを実行できると思います

次に例を示します。

protocol SomeProtocol {
    associatedtype SomeType: RawRepresentable
}

たとえば、RawRepresentableのようなStringのタイプを指定する必要がある場合は、次のようにできます。

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

これで、enumStringであるRawRepresentable以外のものでプロトコルを実装しようとすると、コンパイラエラーが発生します。お役に立てば幸いです。

5
Robin Dorpe