[英]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.