如何访问协议中声明为默认函数并使用其他协议中的关联类型的函数? [英] How do I access a function declared as a default in a protocol and using an associated type from another protocol?
问题描述
昨天我问了一个问题。
上下文:
我有一个 struct
s(称为Vector2D,Vector3D等),代表各种尺寸的向量。它们的实现非常相似,但是由于继承不能用于 struct
,因此我使用了 protocol
(VectorProtocol)将默认成员函数编写为协议扩展
,而不是为每个结构
重复它们。
I have a family of struct
s (called Vector2D, Vector3D, etc) which represent vectors in various dimensions. 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
.
类似地,我有一个 struct
s家族(称为Point2D,Point3D等),它们表示各个维度的点。它们的实现也非常相似,因此出于相同的原因,我使用另一个协议(PointProtocol)。
Similarly, I have a family of struct
s (called Point2D, Point3D, etc) which represent points in various dimensions. Their implementations are also very similar so I use another protocol (PointProtocol) for the same reason.
在每种情况下,协议都使用 associatedtype
来标识特定的 struct
实例类型。
In each case the protocols use associatedtype
s to identify the particular struct
instance type.
有时PointxD和VectorxD交互,所以 PointProtocol
还具有 associatedtype
来标识需要处理的特定VectorxD,以及 VectorProtocol
具有 associatedtype
来标识需要处理的特定PointxD。
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.
到目前为止,一切正常,包括点和向量之间的相互作用。例如,两个点之间的差是一个向量,一个点与一个向量的和是一个点,我可以定义一次运算符来处理每个维的这些情况,如下所示:
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 { /*…*/ }
}
问题:
现在我想再添加一个 struct
s系列(称为Line2D,Line3D等),它们代表各种尺寸的线,其中与点和向量交互。我以为我在做更多相同的事情,但是有细微的差别。线由点和向量组成。
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. 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) { … }
}
它涉及到使用Point2D和Vector2D构造Line2D。但是,当涉及到此默认声明时,编译器会冒充:
This causes no problem when it comes to constructing, for example, a Line2D using a Point2D and a Vector2D. 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'
}
}
似乎编译器找不到运算符声明公共静态函数+(lhs:PointType,rhs:VectorType)-> PointType
即使 anchor
显然是类型 PointProtocol
,而方向显然是<$类型c $ c> VectorProtocol 。所以我认为 endOfLineSegment()
知道锚点和方向分别是PointType和VectorType,这意味着它也应该知道它们也是PointProtocol和Vector Protocol,但它不知道如何为这些协议设置两个关联类型
。
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
. 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.
有人知道如何解决此问题吗? (不必在每个有效的 struct
声明中单独实现该函数)
Does anybody know how to fix this? (Without having to implement the function individually in each struct
declaration which does work)
下面找到足够的代码来在操场上生成错误
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())
推荐答案
事实证明,只有VectorType引起了问题,可以通过添加此约束来解决问题!
It turns out it was only the VectorType causing the problem and it could be solved by adding this constraint!!
extension LineProtocol where Self.VectorType == Self.PointType.VectorType {
// Constraint passes VectorType thru to the PointProtocol
public func endOfLineSegment() -> PointType {
return (anchor + direction)
}
}
这篇关于如何访问协议中声明为默认函数并使用其他协议中的关联类型的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!