如何访问协议中声明为默认函数并使用其他协议中的关联类型的函数? [英] How do I access a function declared as a default in a protocol and using an associated type from another protocol?

查看:77
本文介绍了如何访问协议中声明为默认函数并使用其他协议中的关联类型的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天我问了一个问题

上下文:

我有一个 struct s(称为Vector2D,Vector3D等),代表各种尺寸的向量。它们的实现非常相似,但是由于继承不能用于 struct ,因此我使用了 protocol (VectorProtocol)将默认成员函数编写为协议扩展,而不是为每个结构重复它们。

I have a family of structs (called Vector2D, Vector3D, etc) which represent vectors in various dimensions. Their implementations are very similar but since inheritance is not available for structs 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 structs (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 associatedtypes 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 structs (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 associatedtypes 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆