为什么“即使有不同的条件界限,也不能有多个一致性”?

Val*_*nko 9 generics swift swift-extensions swift-protocols

我希望 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)
Run Code Online (Sandbox Code Playgroud)

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

错误:“E”与协议“P”的一致性冲突;不能有多个一致性,即使有不同的条件边界 extension E: P where T.Prop == String {

注意:“E”在此处声明符合协议“P” 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))
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

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

Ale*_*ica 7

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

它的名称是“重叠一致性”,它被明确和有意地拒绝。您可以在SE-0143 条件一致性的“考虑的替代方案”部分中找到基本原理。TL;DR 是:因为它真的很复杂。

在不知道更多关于你到底想用它做什么的情况下,我们可以提供的方向不多。


小智 7

如前所述,您不能只进行这种扩展。但是,您可以像这样使用 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()
Run Code Online (Sandbox Code Playgroud)

在控制台你可以看到

String
Int
Run Code Online (Sandbox Code Playgroud)