簡體   English   中英

如何訪問在協議中聲明為默認值的 function 並使用來自另一個協議的關聯類型?

[英]How do I access a function declared as a default in a protocol and using an associated type from another protocol?

昨天我問了一個問題 這是一個嘗試將 state 的問題更清楚。

上下文:

我有一個struct家族(稱為 Vector2D、Vector3D 等),它們表示各種維度的向量。 它們的實現非常相似,但由於 inheritance 不適用於struct我使用protocol (VectorProtocol),它使我能夠將默認成員函數編寫為protocol extensions ,而不是為每個struct重復它們。

同樣,我有一系列struct (稱為 Point2D、Point3D 等),它們表示各種維度的點。 它們的實現也非常相似,所以出於同樣的原因我使用了另一個協議(PointProtocol)。

在每種情況下,協議都使用associatedtype來標識特定的struct實例類型。

有時 PointxDs 和 VectorxDs 交互,因此PointProtocol也有一個associatedtype類型來識別它需要處理的特定 VectorxD,而VectorProtocol有一個associatedtype類型來識別它需要處理的特定 PointxD。

到目前為止,一切正常,包括點和向量之間的交互。 例如,兩個點之間的差異是一個向量,一個點和一個向量的總和是一個點,我可以定義一次運算符來處理每個維度的這些情況,如下所示:

public protocol PointProtocol {
    associatedtype VectorType: VectorProtocol
    /*    etc.  */
}

extension PointProtocol {
    public static func +(lhs: Self, rhs: VectorType) -> Self { /*…*/ }
    public static func -(lhs: Self, rhs: Self) -> VectorType { /*…*/ }
}

問題:

現在我想添加更多的struct家族(稱為 Line2D、Line3D 等),它們表示各種維度的線並與點和向量交互。 我以為我在做更多相同的事情,但有細微的差別。 點和向量組成。

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

public struct Line2D: LineProtocol {
    public typealias PointType = Point2D
    public typealias VectorType = Vector2D
    var anchor: PointType
    var direction: VectorType
    public init(anchor: Point2D, direction:Vector2D) { … }
}

例如,在使用 Point2D 和 Vector2D 構建 Line2D 時,這不會造成任何問題。 但是,當涉及到這個默認聲明時,編譯器會猶豫:

extension LineProtocol {
    public func endOfLineSegment() -> PointType {
        return (anchor + direction)    // Compiler ERROR
            // Binary operator '+' cannot be applied to operands of type
            // 'Self.PointType' and 'Self.VectorType'
    }
}

看起來編譯器無法找到運算符聲明public static func +(lhs: PointType, rhs: VectorType) -> PointType即使anchor顯然是PointProtocol類型並且方向顯然是VectorProtocol類型。 所以我認為endOfLineSegment()知道 anchor 和 direction 分別是 PointType 和 VectorType ,這意味着它也應該知道它們是 PointProtocol 和 Vector Protocol ,但它不知道如何為這些協議設置兩個associatedtype

有人知道如何解決這個問題嗎? (無需在每個有效的struct聲明中單獨實現 function)

下面找到足夠的最小代碼來在操場上生成錯誤

public protocol PointProtocol {
   associatedtype PointType: 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())

事實證明,這只是導致問題的 VectorType,可以通過添加此約束來解決!

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM