简体   繁体   English

如何访问在协议中声明为默认值的 function 并使用来自另一个协议的关联类型?

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

相关问题 在另一个协议中重用协议中的关联类型 - Reuse associated type from protocol in another protocol 使用从另一个协议继承的协议作为关联类型 - Use protocol that inherits from another protocol as an associated type 如何使用带有关联类型的协议使用类型擦除 - How can I use Type Erasure with a protocol using associated type 对另一个协议关联类型的协议限制 - Protocol restriction on another protocol associated type 如何使用具有相关类型的协议数组定义协议 - How to define a protocol with an array of a protocol with an associated type 如何使协议关联类型需要协议继承而不是协议采用 - How to make protocol associated type require protocol inheritance and not protocol adoption 如何使用关联类型协议作为函数的参数类型? - How to use associated type protocol as argument's type to a function? 当协议具有关联类型时,从常规方法调用协议默认实现 - Calling protocol default implementation from regular method, when protocol has associated type 符合协议的协议相关类型 - Protocol associated type that conforms to a protocol 具有从AnyObject继承的关联类型的通用协议不会将其他协议视为从AnyObject继承 - Generic protocol with an associated type inheriting from AnyObject does not see another protocol as inheriting from AnyObject
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM