我有一个协议,Address该协议继承自另一个协议Validator,并且Address满足Validator扩展要求。
Address
Validator
还有另一种协议,FromRepresentable其要求associatedType(ValueWrapper)应该为Validator。
FromRepresentable
associatedType
ValueWrapper
现在,如果我尝试使用Addressas associatedType,那么它将无法编译。它说,
推断的类型“地址”(通过匹配要求“ valueForDetail”)无效:不符合“ Validator”。
这种用法非法吗?我们不能像所有的那样用Address它代替。Validator``Addresses``Validator
Validator``Addresses``Validator
下面是我正在尝试的代码。
enum ValidationResult { case Success case Failure(String) } protocol Validator { func validate() -> ValidationResult } //Address inherits Validator protocol Address: Validator { var addressLine1: String {get set} var city: String {get set} var country: String {get set} } ////Fulfill Validator protocol requirements in extension extension Address { func validate() -> ValidationResult { if addressLine1.isEmpty { return .Failure("Address can not be empty") } return .Success } } protocol FormRepresentable { associatedtype ValueWrapper: Validator func valueForDetail(valueWrapper: ValueWrapper) -> String } // Shipping Address conforming to Address protocol. // It should also implicitly conform to Validator since // Address inherits from Validator? struct ShippingAddress: Address { var addressLine1 = "CA" var city = "HYD" var country = "India" } // While compiling, it says: // Inferred type 'Address' (by matching requirement 'valueForDetail') is invalid: does not conform // to 'Validator'. // But Address confroms to Validator. enum AddressFrom: Int, FormRepresentable { case Address1 case City case Country func valueForDetail(valueWrapper: Address) -> String { switch self { case .Address1: return valueWrapper.addressLine1 case .City: return valueWrapper.city case .Country: return valueWrapper.country } } }
更新: 提交了一个错误。
David已经提到的问题是,一旦将协议限制associatedtype为特定的(非@objc)协议,就必须使用具体的类型来满足该要求。
associatedtype
@objc
这是因为协议不符合自己-所以这意味着你不能使用Address,以满足类型的协议的关联型需求符合Validator,因为Address是 不是 一个类型符合Validator。
如我在此处的答案所示,请考虑以下反例:
protocol Validator { init() } protocol Address : Validator {} protocol FormRepresentable { associatedtype ValueWrapper: Validator } extension FormRepresentable { static func foo() { // if ValueWrapper were allowed to be an Address or Validator, // what instance should we be constructing here? // we cannot create an instance of a protocol. print(ValueWrapper.init()) } } // therefore, we cannot say: enum AddressFrom : FormRepresentable { typealias ValueWrapper = Address }
最简单的解决方案是放弃关联类型Validator上的协议约束ValueWrapper,从而允许您在方法参数中使用抽象类型。
protocol FormRepresentable { associatedtype ValueWrapper func valueForDetail(valueWrapper: ValueWrapper) -> String }
enum AddressFrom : Int, FormRepresentable { // ... func valueForDetail(valueWrapper: Address) -> String { // ... } }
如果您需要关联的类型约束,并且每个AddressFrom实例仅期望一个具体的实现Address作为输入–您可以使用泛型,以便AddressFrom使用在方法中使用的给定具体地址类型进行初始化。
AddressFrom
protocol FormRepresentable { associatedtype ValueWrapper : Validator func valueForDetail(valueWrapper: ValueWrapper) -> String }
enum AddressFrom<T : Address> : Int, FormRepresentable { // ... func valueForDetail(valueWrapper: T) -> String { // ... } }
// replace ShippingAddress with whatever concrete type you want AddressFrom to use let addressFrom = AddressFrom<ShippingAddress>.Address1
但是,如果您同时需要关联的类型约束, 并且 每个AddressFrom实例必须能够处理任何类型的输入,则Address必须使用类型擦除来将任意Address类型包装为具体类型。
struct AnyAddress : Address { private var _base: Address var addressLine1: String { get {return _base.addressLine1} set {_base.addressLine1 = newValue} } var country: String { get {return _base.country} set {_base.country = newValue} } var city: String { get {return _base.city} set {_base.city = newValue} } init(_ base: Address) { _base = base } }
enum AddressFrom : Int, FormRepresentable { // ... func valueForDetail(valueWrapper: AnyAddress) -> String { // ... } }
let addressFrom = AddressFrom.Address1 let address = ShippingAddress(addressLine1: "", city: "", country: "") addressFrom.valueForDetail(AnyAddress(address))