在Swift中遵循具有相同变量名的协议时如何避免无限循环?

时间:2020-05-29 22:39:53

标签: swift protocols

在FooModule中提供以下协议:

protocol Id {
    var id: String { get }
}

protocol Foo {
    var id: Id { get }
}

...以及来自ThirdPartyModule的某些类型不符合该类型,但已经具有属性id

struct 3rdPartyId {
   var id: String
}

struct 3rdPartyElement {
    var id: 3rdPartyId
}

现在我要制作:

extension 3rdPartyId: MyModule.Id {
    var id: String { return self.id }
}

extension 3rdPartyElement: MyModule.Element {
    var id: MyModule.Id { return self.id }
}

但是,这将导致无限循环。

如何在没有无限循环的情况下扩展3rdPartyElement使其符合MyModule.Element协议?

我也尝试过这样声明:

extension 3rdPartyElement: MyModule.Element {}

...,因为已经存在应满足协议类型的属性id。但是,这也不起作用,我收到一个编译器错误,告诉我添加属性getter,这当然会造成循环。

1 个答案:

答案 0 :(得分:0)

这是我想出的:

public enum Bar {
    @frozen
    public struct Id {
        private var _id: String = ""
        public var id: String {
            get { _id }
            set { _id = newValue }
        }
        public init(id: String) {
            _id = id
        }
    }

    @frozen
    public struct Bar {
        public var id: Id
    }
}

// MARK: - Protocols

protocol Id {
    var id: String { get }
}

protocol Foo {
    var id: Id { get }
}

// MARK: - Conformance

// (1) Declare that the type conforms to the protocol 
//     (won't compile without the second extension below)
extension Bar.Id: Id {}

// (2) Extend the protocol enough to ensure the compiler
//     knows how the protocol conformance declared in (1)
//     is supposed to actually work.  
extension Id where Self == Bar.Id {
    var id: String { self.id }
    init(id: String) {
        self.init(id: id)
    }
}

// (1) Declare that the type conforms to the protocol 
//     (won't compile without the second extension below)
extension Bar.Bar: Foo {}

// (2) Extend the protocol enough to ensure the compiler
//     knows how the protocol conformance declared in (1)
//     is supposed to actually work.  
extension Foo where Self == Bar.Bar {
    var id: Id { self.id }
}

关键是您需要两个扩展:一个扩展声明该类型符合协议,另一个扩展使用where子句扩展协议并提供必要的粘合使编译器确信所讨论的类型可以满足协议的要求。

这仅起作用是因为协议扩展内的功能主体/属性访问器具有特殊功能,该功能仅对协议扩展有效(对结构/类的扩展无效)。

协议扩展的特殊功能是扩展中的实现可以访问结构或类的原始实现,即相同变量或函数的初始实现,该变量或函数在符合要扩展协议的任何类型内声明并且符合where子句的要求。

由于协议扩展的这种特殊功能,以下内容并非无限循环:

extension Foo where Self == Bar.Bar {
    var id: Id { self.id }
}