为什么编译器看不到协议中的默认代码?

Why does the compiler not see the default code in a protocol?

编辑:我已经重申并希望在 here 上澄清这个问题。现在我已经添加了解决方案。

我定义了一个函数(参见附加示例中的 foo())作为采用我的 protocolstruct 的默认函数。它应用针对其他两个变量定义的 + 运算符,这些变量本身采用其他 protocols 并且 + 在其中一个协议中定义。使用 associatedtypes 键入变量。 我收到消息:

Binary operator '+' cannot be applied to operands of type 'Self.PointType' and 'Self.VectorType'

如果我在我的 struct 中实现该功能(请参阅附件中的 bar() )它会起作用,所以我确信我的 + 运算符确实起作用。 我的示例被精简到在操场上工作所需的最低限度。只需删除 LineProtocol extension 中的注释即可得到错误。在我看来 Self.PointTypePointSelf.VectorTypeVector.

说明一下:我之所以使用associatedtype是因为很多不同的struct都采用了示例中的三种协议,所以我不能直接命名它们

public protocol PointProtocol {
   associatedtype VectorType: VectorProtocol
   var elements: [Float] { get set }
}

extension PointProtocol {
   public static func +(lhs: Self, rhs:VectorType) -> Self {
      var translate = lhs
      for i in 0..<2 { translate.elements[i] += rhs.elements[i] }
      return translate
   }
}

public protocol VectorProtocol {
   associatedtype VectorType: VectorProtocol
   var elements: [Float] { get set }
}

public struct Point: PointProtocol {
   public typealias PointType = Point
   public typealias VectorType = Vector
   public var elements = [Float](repeating: 0.0, count: 2)

   public init(_ x: Float,_ y: Float) {
      self.elements = [x,y]
   }
}

public struct Vector: VectorProtocol {
   public typealias VectorType = Vector
   public static let dimension: Int = 2
   public var elements = [Float](repeating:Float(0.0), count: 2)

   public init(_ x: Float,_ y: Float) {
      self.elements = [x,y]
   }
}

public protocol LineProtocol {
   associatedtype PointType: PointProtocol
   associatedtype VectorType: VectorProtocol
   var anchor: PointType { get set }
   var direction: VectorType { get set }
}

extension LineProtocol {
//   public func foo() -> PointType {
//      return (anchor + direction)
//   }
}

public struct Line: LineProtocol {
   public typealias PointType = Point
   public typealias VectorType = Vector
   public var anchor: PointType
   public var direction: VectorType

   public init(anchor: Point, direction: Vector) {
      self.anchor = anchor
      self.direction = direction
   }

   public func bar() -> Point {
      return (anchor + direction)
   }
}

let line = Line(anchor: Point(3, 4), direction: Vector(5, 1))
print(line.bar())
//print(line.foo())

根据@Honey 的建议改编的解决方案: 将扩展名替换为:

extension LineProtocol where Self.VectorType == Self.PointType.VectorType {
   public func foo() -> PointType {
      // Constraint passes VectorType thru to the PointProtocol
      return (anchor + direction)
   }
}

我知道问题出在哪里了。不确定我的解决方案是否是最佳答案。

问题是您的两个关联类型本身都有关联类型。

因此在扩展中,Swift 编译器无法确定关联类型的类型——除非您对其进行约束。

喜欢:

extension LineProtocol where Self.VectorType == Vector, Self.PointType == Point {
    public func foo() -> Self.PointType {
      return (anchor + direction)
   }
}

您的代码适用于您的具体类型 Line,因为您的两个关联类型都满足了它们的要求,即:

public typealias PointType = Point // makes compiler happy!
public typealias VectorType = Vector  // makes compiler happy!

FWIW 你可以摆脱明确符合你的关联类型要求,让编译器推断 1 符合你的关联类型要求,并将你的 Line 类型写成这样:

public struct Line: LineProtocol {

   public var anchor: Point
   public var direction: Vector

   public init(anchor: Point, direction: Vector) {
      self.anchor = anchor
      self.direction = direction
   }

   public func bar() -> Point {
      return (anchor + direction)
   }
}

1: Generics - Associated Types

Thanks to Swift’s type inference, you don’t actually need to declare a concrete Item of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate Item to use, simply by looking at the type of the append(_:) method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias Item = Int line from the code above, everything still works, because it’s clear what type should be used for Item.