gpt4 book ai didi

ios - 无法在 Swift 中使用协议(protocol)作为另一个协议(protocol)中的关联类型

转载 作者:行者123 更新时间:2023-11-30 13:11:00 25 4
gpt4 key购买 nike

我有一个协议(protocol)Address,它继承自另一个协议(protocol)Validator,并且Address满足Validator > 扩展中的要求。

还有另一个协议(protocol),FromRepresentable,它有一个 linkedType (ValueWrapper) 要求,应该是 Validator

现在,如果我尝试使用 Address 作为 linkedType,则它无法编译。它说,

Inferred type 'Address' (by matching requirement 'valueForDetail') is invalid: does not conform to 'Validator'.

这种用法违法吗?我们是否应该能够使用 Address 代替 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
}
}
}

更新:提交了bug.

最佳答案

问题,哪个David has already alluded to ,一旦您将协议(protocol)的 linkedtype 限制为特定的(非 @objc)协议(protocol),您就必须使用具体类型来满足该要求。

这是因为protocols don't conform to themselves – 因此意味着您不能使用 Address 来满足符合 Validator 的协议(protocol)的关联类型要求,因为 Address不是符合Validator的类型。

正如我所演示的 in my answer here ,考虑以下反例:

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
}

最简单的解决方案是放弃对 ValueWrapper 关联类型的 Validator 协议(protocol)约束,从而允许您在方法参数中使用抽象类型。

protocol FormRepresentable {
associatedtype ValueWrapper
func valueForDetail(valueWrapper: ValueWrapper) -> String
}

enum AddressFrom : Int, FormRepresentable {

// ...

func valueForDetail(valueWrapper: Address) -> String {
// ...
}
}

如果您需要关联的类型约束,并且每个 AddressFrom 实例仅期望 Address 的单个具体实现作为输入 - 您可以使用泛型来为您的 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 输入– 您将使用类型删除来将任意地址包装在具体类型中。

protocol FormRepresentable {
associatedtype ValueWrapper : Validator
func valueForDetail(valueWrapper: ValueWrapper) -> String
}

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

关于ios - 无法在 Swift 中使用协议(protocol)作为另一个协议(protocol)中的关联类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38739677/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com