Swift:用于枚举的协议不';行不通

Swift:用于枚举的协议不';行不通,swift,enums,ios8,protocols,Swift,Enums,Ios8,Protocols,对于枚举,我需要的协议定义的一部分是保存一个以“self”作为密钥的字典。这是我第一次尝试: protocol Orderable { // line 1 class var first: Self { get } class var last: Self { get } class var strings: [Self : String] { get } // line 4 } enum Item

对于枚举,我需要的协议定义的一部分是保存一个以“self”作为密钥的字典。这是我第一次尝试:

protocol Orderable {                               // line 1
    class var first: Self { get }
    class var last: Self { get }  
    class var strings: [Self : String] { get }     // line 4
}

enum Item : Int, Orderable {
   case ItemA = 0, ItemB, ItemC
   static let last : Item = Item.ItemC

   var name : String { return Item.strings[self]! }

   static let strings: [Item : String] = [ 
        .Item1: "item no. 1", .Item2 : "item no. 2", .Item3: "Item no. 3"
   ]
}

println ("last item is: \(Item.last.name)")    // ==> "last item is: item no. 3"
在第4行失败,错误为:

类型“Self”不符合协议“Hashable”

为了解决这个问题,我尝试从Hashable继承Orderable,如下所示:

protocol Orderable : Hashable { ...  }
然而,当我尝试这样做时,游乐场崩溃了


这是解决问题的正确方法吗

操场崩溃的问题不在于你的
Orderable
协议,而在于你的
项目
枚举。确实,
Orderable
需要实现
Hashable
才能工作,但您在操场上看到的问题更多地是由于
项目
没有正确实现
Orderable
。当代码编写得不正确时,游戏场仍然相当不稳定,所以它对您造成的冲击对我来说并不太奇怪

因此,要解决Xcode 6.0中的编译器错误,您需要执行以下操作:

注意:如果您使用的是Xcode 6.1,请参阅更新

Orderable
协议中,您已将
第一个
最后一个
字符串
定义为只读计算属性,但已将它们定义为
枚举中的读写存储属性。此外,您还忽略了实现第一个属性

而不是定义最后一个,例如:

static let last : Item = Item.ItemC
它需要定义为一个
var
,其表达式
返回
s
项。项c

static var last : Item { return Item.ItemC }
同样的基本思想可以应用于
第一个
字符串

另外,在
字符串
属性中,您使用了
.Item1
.Item2
.Item3
,而不是
.ItemA
.ItemB
.ItemC

因此,如果我们解决了所有问题:

protocol Orderable: Hashable {
    class var first: Self { get }
    class var last: Self { get }
    class var strings: [Self : String] { get }
}

enum Item : Int, Orderable {
    case ItemA = 0, ItemB, ItemC

    static var first: Item { return .ItemA }
    static var last : Item { return .ItemC }
    static var strings: [Item: String] {
        return [
            .ItemA: "item no. 1", .ItemB : "item no. 2", .ItemC: "Item no. 3"
        ]
    }

    var name : String { return Item.strings[self]! }
}
这与此快速测试配合得很好:

println("last item is: \(Item.last.name)")
println("first item is: \(Item.first.name)")
println("item B is \(Item.strings[Item.ItemB])")
产出:

最后一项是:第3项

第一项是:第1项

B项为可选项(“第2项”)


更新:正如@David在评论中指出的那样,我上面所说的关于在
项中实现
Orderable
协议属性的内容似乎只是Xcode 6.0中的一个问题。在Xcode 6.1中,以最初的方式实现属性是完全合理的。在Xcode 6.1游乐场中,这可以正常工作:

protocol Orderable: Hashable {
    class var first: Self { get }
    class var last: Self { get }
    class var strings: [Self : String] { get }
}

enum Item : Int, Orderable {
    case ItemA = 0, ItemB, ItemC

    static var first: Item = .ItemA
    static var last : Item = .ItemC
    static var strings: [Item: String] = [
        .ItemA: "item no. 1", .ItemB : "item no. 2", .ItemC: "Item no. 3"
    ]

    var name : String { return Item.strings[self]! }
}

他的主要问题是,他没有将Orderable声明为Hashable的扩展,而您已经将其作为解决他许多其他问题的副作用进行了修复。协议中的定义
classvar-first:Self{get}
只是说协议要求必须有一个get方法。实现上没有任何限制,实际上,您可以使用get和set方法来实现它,尽管6.0编译器似乎有问题。在6.1编译器上,这似乎很好。@David他们在问题中确实说,他们试图将
Orderable
声明为
Hashable
,我在回答中重申了这一点,所以我认为已经涵盖了这一点。我的观点主要是,由于代码中的其他问题,它无法工作(在他们的例子中,操场正在崩溃)。回复:对属性实现的限制,我没有意识到,谢谢。当时我正在使用6.0编译器,但后来我安装了6.1 GM,我知道你是对的。我将更新答案以反映这一点。是的,我只是想指出,您正在处理一个编译器错误,它的编写方式应该很好。我去掉了很多东西,包括Hashable,把它精简到变量声明和定义的最小值,它仍然在6.0上崩溃。使用一种距离生产就绪还有很长一段路要走的语言(和实现)的荣耀。顺便说一句,也可以将first、last等定义为
var
,并使它们也是可变的。虽然实际上分配给它会使操场崩溃…哎呀,我实际上是想在我的编辑中制作那些
var
s;谢谢你指出这一点。我还调整了我最初的答案,指出这部分是为了解决编译器错误。也许有一天我们不必在Swift中做太多的变通方法……有些人认为发布未注释的代码而没有文本描述或解释是不好的风格——也就是说,这个答案被标记为低质量
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}

enum SimpleEnum : ExampleProtocol {
    case enumMember(String)
        var simpleDescription: String {
            get {
                switch self {
                    case let .enumMember(descript):
                        return descript
                }
            }
    }
    mutating func adjust () {
        switch self {
            case let .enumMember(desc):
                self = .enumMember(desc + " (adjusted)")
        }
    }
}

var c = SimpleEnum.enumMember("A simple enum.")
var csimpleDescription = c.simpleDescription
c.adjust()
var dsimpleDescription = c.simpleDescription