为什么 'there cannot be more than one conformance, even with different conditional bounds'?

Why 'there cannot be more than one conformance, even with different conditional bounds'?

我希望 Swift 能够为 where 块中具有指定条件的类型创建扩展。我想象我可以根据具体的通用类型值 (T) 使用不同的扩展来扩展相同的通用类型。但不是。以下示例演示了我的问题:

protocol P {    
    associatedtype Prop 
    var property: Prop { get }
}

enum E<T: P> {
   case single(T)
   case double(T)
}

extension E: P where T.Prop == Int {
   var property: Int {
      switch self {
      case .single(let o): return o.property
      case .double(let o): return o.property * 2
      }
   }
}

extension E: P where T.Prop == String {
   var property: String {
      switch self {
      case .single(let o): return o.property
      case .double(let o): return o.property + o.property
      }
   }
}

struct Int4: P {
   var property: Int {
       return 4
   }
}

struct StringHello: P {
    var property: String {
        return "Hello" 
    }
}

print(E.single(Int4()).property)
print(E.double(StringHello()).property)

以下错误和注释是编译的结果。

error: conflicting conformance of 'E' to protocol 'P'; there cannot be more than one conformance, even with different conditional bounds extension E: P where T.Prop == String {

note: 'E' declares conformance to protocol 'P' here extension E: P where T.Prop == Int {

真的不可能吗?为什么?我如何使用我的代码才能成功?


在我的真实情况下展示问题的一些细节。
我有一些通用枚举,用于许多不同的包装类型。

enum Color<T> {
  case red(T), green(T)

  func map<T2>(_ transform: (T) -> T2) -> Color<T2> {
    switch self {
    case .red(let o): return .red(transform(o))
    case .green(let o): return .green(transform(o))
    }
  }
}

很多时候,我需要对 Color 进行不同的扩展,以根据包装类型使其符合不同的协议。有时这些协议具有相同的基础(超级)协议,因此,我遇到了当前的问题。有时我无法扩展 Color 以符合所有派生协议的基本(超级)协议,因为我需要不同的实现。

不可能吗?是和不是。目前在 Swift 中不可能,因为它已经实现了。原则上是可以实现的。

它的名字是 "overlapping conformances",它被明确且有意地拒绝了。您可以在 SE-0143 Conditional conformances 的 "Alternatives considered" 部分找到基本原理。 TL;DR 是:因为它真的很复杂。

在不了解您尝试使用它的具体用途的情况下,我们无法提供太多指导。

如前所述,您不能只进行这种扩展。但是,您可以像这样使用 hack:

protocol SomeExtension {
    func doSomething()
}

extension SomeExtension {
    func doSomething() {
        print("Do nothing or error")
    }
}

extension SomeExtension where Self == [String] {
    func doSomething() {
        print("String")
    }
}

extension SomeExtension where Self == [Int] {
    func doSomething() {
        print("Int")
    }
}

extension Array: SomeExtension { }

let stringsArr = ["a", "b", "d"]
let numbersArr = [1, 2, 3]
stringsArr.doSomething()
numbersArr.doSomething()

在控制台你可以看到

String
Int