2

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

我已经定义了一个函数(见foo()附件示例)作为structs 采用 my protocol. 它应用+针对其他两个变量定义的运算符,这些变量本身采用其他变量protocols+在其中一个协议中定义。变量使用associatedtypes 输入。我收到消息:

二元运算符“+”不能应用于“Self.PointType”和“Self.VectorType”类型的操作数

如果我在我的内部实现该函数struct(参见附件中的 bar())它可以工作,所以我确信我的 + 运算符确实有效。我的例子被缩减到在操场上工作所需的最低限度。只需删除中的注释LineProtocol extension即可获得错误。在我看来,这Self.PointType是 aPoint并且Self.VectorTypeVector.

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

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

4

1 回答 1

1

我知道问题是什么。不确定我的解决方案是否是最佳答案。

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

所以在扩展中,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,您本可以摆脱对您的 associatedtype 要求的显式一致性,并让编译器推断出1符合您的 associatedtypes 要求并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:泛型 - 关联类型

由于 Swift 的类型推断,您实际上不需要将 Int 的具体 Item 声明为 IntStack 定义的一部分。因为 IntStack 符合 Container 协议的所有要求,Swift 可以推断出要使用的适当 Item,只需查看 append(_:) 方法的 item 参数的类型和下标的返回类型。事实上,如果你从上面的代码中删除 typealias Item = Int 行,一切仍然有效,因为很清楚应该为 Item 使用什么类型。

于 2019-11-05T14:29:37.937 回答