为什么不能将我的二进制运算符应用于正确类型的操作数?

时间:2019-07-16 10:28:47

标签: swift generics binary-search-tree associated-types

我正在构建一个二进制搜索树,其中将包含对象(我称它们为记录),这些对象的类型我事先都不知道。该树将由排序,该键是Record的一部分(再次未知)。因此,我选择了泛型,即符合要求其包含密钥的协议的记录和符合要求其具有对两个键进行排序的运算符的协议的密钥。

infix operator ⊰: ComparisonPrecedence

public enum Comparator {
   case matching
   case leftTree
   case rightTree
}

public protocol RecordProtocol {
   associatedtype Key: KeyProtocol
   var key: Key { get }
}

public protocol KeyProtocol {
   static func ⊰(lhs: Self,rhs: Self) -> Comparator
}

public enum Tree<R: RecordProtocol, K: KeyProtocol> {
   case empty
   indirect case node(_ record: R,_ left: Tree<R,K>,_ right: Tree<R,K>)
   public init() {
      self = .empty
   }
}

//This compiles perfectly fine
//Now I add a function to see if the tree contains a particular key

extension Tree {
   public func contains(_ key: K) -> Bool {
      switch self {
      case .empty:
         return false
      case let .node(record, left, right):
         switch key ⊰ record.key {
         case .matching: return true
         case .leftTree: return left.contains(key)
         case .rightTree: return right.contains(key)
         }
      }
   }
}

switch 语句无法编译以下消息:

Binary operator '⊰' cannot be applied to operands of type 'K' and 'R.Key'

据我所知, record.key 都是 KeyProtocol 的实例,并且应该可供比较运算符< strong>⊰

有人可以解释吗?

1 个答案:

答案 0 :(得分:2)

您需要确保KR.Key属于同一类型,因为您定义了自定义运算符以接受两个相同类型的输入参数。

extension Tree where K == R.Key {
    public func contains(_ key: K) -> Bool {
        switch self {
        case .empty:
            return false
        case let .node(record, left, right):
            switch key ⊰ record.key {
            case .matching: return true
            case .leftTree: return left.contains(key)
            case .rightTree: return right.contains(key)
            }
        }
    }
}

或者您可以修改Tree本身以确保KR.Key始终是同一类型。

public enum Tree<R: RecordProtocol, K> where R.Key == K {
    case empty
    indirect case node(_ record: R,_ left: Tree<R,K>,_ right: Tree<R,K>)
    public init() {
        self = .empty
    }
}

extension Tree {
    public func contains(_ key: K) -> Bool {
        switch self {
        case .empty:
            return false
        case let .node(record, left, right):
            switch key ⊰ record.key {
            case .matching: return true
            case .leftTree: return left.contains(key)
            case .rightTree: return right.contains(key)
            }
        }
    }
}