在Swift中,我如何指定一个类型别名来限制rawrepresable为String



我正在尝试定义一个协议,需要一个原始值Stringenum来实现。

我不相信目前有可能强制使用enum,我不确定我真的关心,只要在某个地方我可以调用fromRaw()并接收String

所以,我试图保持以下的简洁性,同时限制Betaenum,其中原始值是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不同,以限制RawRepresentableString ?


<标题> 更新

指定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

虽然这在技术上防止使用String以外的任何东西,但我正在寻找编译时约束,这似乎会导致运行时异常。

如果可能的话,我更希望协议强制执行这一点,而不是消费者需要检查.Raw == String

只是为了补充一下,因为它有点旧,你更新的例子现在在swift 2+中工作,并且会在编译时抱怨。zeta是模糊的,除非它是一个String类型。

您还可以将检查放在协议扩展的模式匹配中。例如:

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

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

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
    }
}

这类似于苹果在Codable协议中处理CodingKey的方式。我发现它在做诸如在数据库中存储任意类类型之类的事情时很有用。

让我们看看这里的选项。首先,这是一个众所周知的限制(从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

从哲学上讲,这更符合你的需求:你说"我想要的东西不仅是rawrepresable,而且是fromRaw(String)。想想怎么给我的。"Gamma结构体是最简单的例子,消费者指定他的enum,然后说"好,我可以给你我的标准fromRaw(),因为它可以工作。"

我和一个同事讨论过这个问题,在Swift 2.0/2.1中,你可以通过一个协议:https://gist.github.com/designatednerd/5645d286df0ce939714b

在我正在使用的一个应用程序中试用过,效果很好。:)

相关内容

  • 没有找到相关文章

最新更新