为什么编译器看不到协议中的默认代码?

编辑:我已经重申并希望通过here来澄清这个问题。现在,我已经添加了解决方案。

我已经为foo()采用我的struct的默认功能定义了一个函数(请参见附件中的protocol)。它应用针对其他两个变量定义的+运算符,它们本身采用其他protocols,并且+在那些协议之一中定义。使用associatedtype键入变量。 我收到消息:

  

二进制运算符'+'不能应用于类型为'Self.PointType'和'Self.VectorType'的操作数

如果我在struct中实现该函数(请参见附件中的bar()),该函数将起作用,因此,我确定+运算符确实起作用。 我的示例被缩减为在操场上工作所需的最低限度。只需删除LineProtocol extension中的注释即可获得错误。在我看来Self.PointTypePoint,而Self.VectorTypeVector

要清楚:我使用associatedtype的原因是因为示例中许多不同的struct都采用了这三种协议,所以我不能直接命名它们

public protocol 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),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())

解决方案改编自@Honey的建议: 将扩展名替换为:

extension LineProtocol where Self.VectorType == Self.PointType.VectorType {
   public func foo() -> PointType {
      // Constraint passes VectorType thru to the PointProtocol
      return (anchor + direction)
   }
}

ychmail 回答:为什么编译器看不到协议中的默认代码?

我知道问题出在哪里。不知道我的解决方案是否是最佳答案。

问题是两个关联类型本身都具有关联类型。

因此,在扩展名中,Swift编译器无法确定associatedtypes的类型,除非您对其进行约束。

喜欢:

extension LineProtocol where Self.VectorType == Vector,Self.PointType == Point {
    public func foo() -> Self.PointType {
      return (anchor + direction)
   }
}

您的代码适用于您的具体类型Line,因为两个关联类型都满足了它们的要求,即:

public typealias PointType = Point // makes compiler happy!
public typealias VectorType = Vector  // makes compiler happy!

首先,您可以摆脱对您的associatedtype要求的显式一致性,并让编译器推断您对associatedtype要求的 1 符合性,并这样编写您的Line类型:

public struct Line: LineProtocol {

   public var anchor: Point
   public var direction: Vector

   public init(anchor: Point,direction: Vector) {
      self.anchor = anchor
      self.direction = direction
   }

   public func bar() -> Point {
      return (anchor + direction)
   }
}

1:Generics - Associated Types

  

由于Swift的类型推断,您实际上不需要声明一个   Int的具体项目,作为IntStack定义的一部分。因为   IntStack符合Container的所有要求   协议,Swift可以通过以下方式推断要使用的适当项目   查看append(_ :)方法的item参数的类型和   下标的返回类型。确实,如果您删除了typealias项目   =上面代码中的int行,一切仍然有效,因为很清楚应该为Item使用哪种类型。

本文链接:https://www.f2er.com/3159133.html

大家都在问