[英]How do I access a function declared as a default in a protocol and using an associated type from another protocol?
Yesterday I asked a question .昨天我问了一个问题。 This is an attempt to state the question more clearly.
这是一个尝试将 state 的问题更清楚。
THE CONTEXT:上下文:
I have a family of struct
s (called Vector2D, Vector3D, etc) which represent vectors in various dimensions.我有一个
struct
家族(称为 Vector2D、Vector3D 等),它们表示各种维度的向量。 Their implementations are very similar but since inheritance is not available for struct
s I use a protocol
(VectorProtocol) which enables me to write default member functions as protocol extensions
instead of repeating them for each struct
.它们的实现非常相似,但由于 inheritance 不适用于
struct
我使用protocol
(VectorProtocol),它使我能够将默认成员函数编写为protocol extensions
,而不是为每个struct
重复它们。
Similarly, I have a family of struct
s (called Point2D, Point3D, etc) which represent points in various dimensions.同样,我有一系列
struct
(称为 Point2D、Point3D 等),它们表示各种维度的点。 Their implementations are also very similar so I use another protocol (PointProtocol) for the same reason.它们的实现也非常相似,所以出于同样的原因我使用了另一个协议(PointProtocol)。
In each case the protocols use associatedtype
s to identify the particular struct
instance type.在每种情况下,协议都使用
associatedtype
来标识特定的struct
实例类型。
Sometimes PointxDs and VectorxDs interact so PointProtocol
also has an associatedtype
to identify the particular VectorxD it needs to handle and VectorProtocol
has an associatedtype
to identify the particular PointxD it needs to handle.有时 PointxDs 和 VectorxDs 交互,因此
PointProtocol
也有一个associatedtype
类型来识别它需要处理的特定 VectorxD,而VectorProtocol
有一个associatedtype
类型来识别它需要处理的特定 PointxD。
So far, everything works fine, including interaction between points and vectors.到目前为止,一切正常,包括点和向量之间的交互。 For instance the difference between 2 points is a vector and the sum of a point and a vector is a point and I can define operators once to handle these cases for every dimension as follows:
例如,两个点之间的差异是一个向量,一个点和一个向量的总和是一个点,我可以定义一次运算符来处理每个维度的这些情况,如下所示:
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 { /*…*/ }
}
THE PROBLEM:问题:
Now I want to add a further family of struct
s (called Line2D, Line3D, etc) which represent lines in various dimensions and which interact with points and vectors.现在我想添加更多的
struct
家族(称为 Line2D、Line3D 等),它们表示各种维度的线并与点和向量交互。 I thought I was doing more of the same but there is a subtle difference.我以为我在做更多相同的事情,但有细微的差别。 Lines are composed of points and vectors.
线由点和向量组成。
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) { … }
}
This causes no problem when it comes to constructing, for example, a Line2D using a Point2D and a Vector2D.例如,在使用 Point2D 和 Vector2D 构建 Line2D 时,这不会造成任何问题。 However, the compiler baulks when it comes to this default declaration:
但是,当涉及到这个默认声明时,编译器会犹豫:
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'
}
}
It looks like the compiler cannot find the operator declaration public static func +(lhs: PointType, rhs: VectorType) -> PointType
even though anchor
is clearly of type PointProtocol
and direction is clearly of type VectorProtocol
.看起来编译器无法找到运算符声明
public static func +(lhs: PointType, rhs: VectorType) -> PointType
即使anchor
显然是PointProtocol
类型并且方向显然是VectorProtocol
类型。 So I think endOfLineSegment()
knows that anchor and direction are PointType and VectorType respectively, which means it should know that they are PointProtocol and Vector Protocol too, but it does not know how to set the two associatedtype
s for these protocols.所以我认为
endOfLineSegment()
知道 anchor 和 direction 分别是 PointType 和 VectorType ,这意味着它也应该知道它们是 PointProtocol 和 Vector Protocol ,但它不知道如何为这些协议设置两个associatedtype
。
Does anybody know how to fix this?有人知道如何解决这个问题吗? (Without having to implement the function individually in each
struct
declaration which does work) (无需在每个有效的
struct
声明中单独实现 function)
Below find sufficient minimal code to generate the error in a playground下面找到足够的最小代码来在操场上生成错误
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())
It turns out it was only the VectorType causing the problem and it could be solved by adding this constraint!!事实证明,这只是导致问题的 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.