在Swift中,如何指定将RawRepresentable限制为String的类型?

时间:2014-08-09 19:33:10

标签: swift rawrepresentable

我正在尝试定义一个需要enum原始值String的协议。

我不相信目前可以强制使用enum,而且我不确定我真正关心,只要在某个地方,我可以致电{ {1}}并收到fromRaw()

所以,我试图保持以下简洁,同时将String限制为原始值为Beta的{​​{1}}:

enum

上述问题是允许使用其他原始值,因此这是有效的:

String

要解决我目前正在做的事情:

protocol Alpha {
    typealias Beta: RawRepresentable
}

struct Gamma: Alpha {
    enum Beta: String {
        case Delta = "delta"
    }
}

struct Eta<T: Alpha, U: RawRepresentable where T.Beta == U> {
    let alpha: T
    let beta: U
    init(alpha: T, beta: U) {
        self.alpha = alpha
        self.beta = beta
        println("beta is: \(beta.toRaw())")
    }
}

let gamma = Gamma()
Eta(alpha: gamma, beta: .Delta) // "beta is delta"

我是否可以在原始示例中以不同的方式声明struct Epsilon: Alpha { enum Beta: Int { case Zeta = 6 } } let epsilon = Epsilon() Eta(alpha: epsilon, beta: .Zeta) // "beta is 6" 以将protocol StringRawRepresentable: RawRepresentable { class func fromRaw(raw: String) -> Self? } protocol Alpha { typealias Beta: StringRawRepresentable } struct Gamma: Alpha { enum Beta: String, StringRawRepresentable { case Delta = "delta" } } // Type 'Epsilon' does not conform to protocol 'Alpha' struct Epsilon: Alpha { enum Beta: Int { case Zeta = 6 } } struct Eta<T: Alpha, U: StringRawRepresentable where T.Beta == U> { let alpha: T let beta: U init(alpha: T, beta: U) { self.alpha = alpha self.beta = beta println("beta is: \(beta.toRaw())") } } let gamma = Gamma() Eta(alpha: gamma, beta: .Delta) // "beta is delta" 限制为typealias


更新

指定RawRepresentable似乎很有希望,所以我尝试了一下:

String

虽然这在技术上阻止使用U: RawRepresentable where U.Raw == String以外的任何东西,但我正在寻找编译时约束,这似乎导致运行时异常。

如果可能,我也希望协议强制执行,而不是消费者需要检查protocol Alpha { typealias Beta: RawRepresentable } struct Gamma: Alpha { enum Beta: String { case Delta = "delta" } } struct Eta<T: Alpha, U: RawRepresentable where T.Beta == U, U.Raw == String> { let alpha: T let beta: U init(alpha: T, beta: U) { self.alpha = alpha self.beta = beta // Execution was interrupted, reason: EXC_BAD_ACCESS (code=EXC_I386_GPFLT). println("beta is: \(beta.toRaw())") } } let gamma = Gamma() Eta(alpha: gamma, beta: .Delta) // "beta is delta" struct Epsilon: Alpha { enum Beta: Int { case Zeta = 6 } } let epsilon = Epsilon() Eta(alpha: epsilon, beta: .Zeta) // Error only occurs when this is executed

4 个答案:

答案 0 :(得分:4)

只是为了添加它,因为它有点旧,你的更新的例子现在在swift 2+中工作,并且会在编译时抱怨.Zeta是不明确的,除非它是一个String类型。

您还可以将检查放入协议扩展的模式匹配中。举个例子:

extension SequenceType where Generator.Element:RawRepresentable,
                         Generator.Element.RawValue == String {
    func toStringArray() -> [String] {
        return self.map { $0.rawValue }
    }
}

答案 1 :(得分:0)

让我们来看看我们的选择。首先,它是(从Xcode 6 beta 5开始)一个众所周知的限制,我们无法以简单和预期的方式指定枚举类型约束。其次,你需要一些非常明确的东西:能够致电fromRaw(String)。第三,您需要编译器错误。我说你最好的选择是编写一个协议来做到这一点,然后向消费者推送确保他/她给你一个fromRaw(String)的要求。在这种情况下,这就是我要做的,简化您的第二个代码段:

protocol Alpha {
    typealias Beta: RawRepresentable
    func fromRaw(raw: String) -> Beta?
}

struct Gamma: Alpha {
    enum Beta: String {
        case Delta = "delta"
        case Omega = "omega"
    }
    func fromRaw(raw: String) -> Beta? {
        return Beta.fromRaw(raw)
    }
}

struct Eta<T: Alpha, U: RawRepresentable where T.Beta == U> {
    let alpha: T
    let beta: U
    init(alpha: T, beta: U) {
        self.alpha = alpha
        self.beta = beta
        println("beta is: \(beta.toRaw())")
    }
}

let gamma = Gamma()
let a = Eta(alpha: gamma, beta: .Delta) // "beta is delta"
println(gamma.fromRaw("delta"))  // Optional(Enum Value)
println(gamma.fromRaw("omega")!) // Enum Value

哲学上这与你的需求更加一致:你说&#34;我想要的不仅是RawRepresentable,还有fromRaw(String)。弄清楚你是如何把它给我的#34;。 Gamma结构是最简单的例子,消费者特定他的枚举,然后说&#34;好吧,我可以给你我的标准fromRaw(),因为它有效。

答案 2 :(得分:0)

我和一位同事谈到了这一点,在Swift 2.0 / 2.1中,您可以使用协议执行此操作:https://gist.github.com/designatednerd/5645d286df0ce939714b

在我正在使用的应用程序中尝试过它,就像一个魅力。 :)

答案 3 :(得分:0)

现在应该可以了。例如,以下协议允许类定义自己的符合字符串的'input'参数的枚举:

protocol AttributeContainer {
   associatedtype InputKey: RawRepresentable where InputKey.RawValue: StringProtocol
   func set(value: Any?, for inputKey: InputKey)
}

这可以使用如下:

class MyClass: AttributeContainer {

    enum AttributeKey: String {
       case attributeA, attributeB, attributeC
    }

    func set(value: Any?, for inputKey: InputKey) {
        // Handle the setting of attributes here
    }

}

这类似于Apple在CodingKey协议中处理Codable的方式。我发现它在处理数据库中存储任意类类型时很有用。