【问题标题】:Extensions of swift classes and structs behave differentlyswift 类和结构的扩展行为不同
【发布时间】:2015-10-29 10:34:34
【问题描述】:

问题是我有一些结构或类具有符合某些协议的通用约束。当我尝试根据泛型类型 T 添加专门的实现时,它适用于类但不适用于结构。我不能在我的特定用例中使用类,因为这个类应该符合需要初始化器的协议,但我不能在扩展中指定类初始化器。

有什么办法让它工作吗?还是我应该选择另一条路?这是一个演示问题的代码sn-p。

protocol ProtocolA {}
protocol ProtocolB: ProtocolA {}
protocol ProtocolC {
    fun act()
}

struct StructA: ProtocolA {}

struct StructB: ProtocolB {}

struct StructC<T: ProtocolA>: ProtocolC {}

extension StructC {
    func act() {
        print("general")
    }
}

extension StructC where T: ProtocolB {
    func act() {
        print("special")
    }
}

class ClassC<T: ProtocolA>: ProtocolC {
}

extension ClassC {
    func act() {
        print("general")
    }
}

extension ClassC where T: ProtocolB {
    func act() {
        print("special")
    }
}

let classCA = ClassC<StructA>()
let classCB = ClassC<StructB>()

//this works
classCA.act() //-> "general"
classCB.act() //-> "special"

let structCA = StructC<StructA>()
let structCB = StructC<StructB>()

//Does not even compile
structCA.act() 
structCB.act() // error: "Ambigous use of 'act()'"

UPD:如果我使用带有别名类型的协议并扩展协议而不是结构,那么它可以工作:

protocol ProtocolD {
    typealias V
    func act()
}

struct StructD<T: ProtocolA>: ProtocolD {
    typealias V = T
}

extension ProtocolD {
    func act() {
        print("general")
    }
}

extension ProtocolD where V: ProtocolB {
    func act() {
        print("special")
    }
}

let structDA = StructD<StructA>()
let structDB = StructD<StructB>()

//works again
structDA.act() //-> "general"
structDB.act() //-> "special"

但它仍然没有解决或解释类和结构不同行为的问题。

UPD:该问题的归档雷达 rdar://23314307

【问题讨论】:

    标签: swift


    【解决方案1】:

    一开始你就在这里声明

    `let structCB = StructC<StructB>()`
    

    但是用ProtocolB实现扩展,当StructB只继承这个协议时:

    extension StructC where T: ProtocolB {
        func act() {
            print("special")
        }
    }
    

    StructB 继承 ProtocolB,但 ProtocolB 没有“继承”StructB。 如果您对此扩展进行默认实现,它将起作用:

    extension StructC where T: StructB {
        func act() {
            print("special")
        }
    }
    

    更新:

    我终于明白了你的问题,也开始感兴趣——为什么它不起作用。 问题是protocol ProtocolB: ProtocolA {} 然后在通用ProtocolB 中不被视为从ProtocolA 继承。我认为你可以稍微改变一下你的逻辑并解决问题:

    您的 ProtocolB 扩展 ProtocolA 并添加了一些功能,例如。如果可以的话,你可以在StructB添加函数

    【讨论】:

    • 据我所知,当我在扩展中指定类型 T 的约束时,我说这个扩展应该应用于符合此约束的任何类型的 T。所以StructB 符合T: ProtocolB,因为它符合ProtocolB 所以它应该从这个扩展中得到实现。那是错的吗?同样在我的实际用例中,我不能像你建议的那样在扩展中使用具体类。
    • 您能更详细地解释您的建议吗? ProtocolB 正是你所说的 - 在 ProtocolA 之上添加一些功能。只是为了说明无关紧要。如果我在StructB 中添加一些函数而不将它们添加到ProtocolB,我将无法在扩展中访问它们,因为TProtocolB,而不是StructB。我希望所有这些 A 和 B 都不会让人感到困惑......
    • 我也试过不从ProtocolA继承ProtocolB,而是在StructB中分别符合它们,比如:struct StructB: ProtocolA, ProtocolB {},但还是有歧义错误。
    【解决方案2】:

    你错过了mutating

    extension StructC where T: ProtocolB {
        mutating func act() {
            print("special")
        }
    }
    

    【讨论】:

    • @Pravan - 并非结构上的每个方法都应标记为“变异”,并且它不必对所描述的问题做任何事情。
    • @IlyaPuchka 当然,并非每个方法都必须标记为mutating,但在这种情况下,您的扩展程序正在更改self,所以它确实如此。如果您进行更改并运行示例代码,您将看到它可以编译。 developer.apple.com/library/ios/documentation/Swift/Conceptual/…
    • @Pravan - StructC 方法“行为”的哪些方面发生了变化?它不编译。
    • @Pranav 你应该在你的回答中解释你为什么提出这个解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    相关资源
    最近更新 更多