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



编辑:我在这里重申并希望澄清这个问题。现在我添加了解决方案。

我已经定义了一个函数(参见所附示例中的foo()(作为采用我的protocolstruct的默认函数。它应用针对两个其他变量定义的+运算符,这两个变量本身采用其他protocols,并且在这些协议之一中定义了+。变量使用associatedtypes进行类型化。我收到消息:

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

如果我在struct中实现函数(请参阅附件中的bar(((,它会起作用,所以我确信我的+运算符确实起作用。我的例子被简化为在操场上工作所需的最低限度。只需删除LineProtocol extension中的注释即可获得错误。在我看来,Self.PointTypePointSelf.VectorTypeVector

需要明确的是:我之所以使用associatedtypes,是因为许多不同的structs都采用了示例中的三种协议中的每一种,所以我不能直接将它们命名为

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

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

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

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

问题是,您的两个关联类型本身都有关联类型。

因此,在扩展中,Swift编译器无法计算出关联类型的类型——除非您对其进行约束

喜欢做:

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!

FWIW你本可以去掉对关联类型要求的明确一致性,让编译器推断出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:泛型-关联类型

由于Swift的类型推断,您实际上不需要声明Int的具体项,作为IntStack定义的一部分。因为IntStack符合容器的所有要求协议,Swift可以简单地通过查看append(_:(方法的项参数的类型和返回下标的类型。事实上,如果您删除typealias Item=上面代码的Int行,一切仍然有效,因为很清楚Item应该使用什么类型。

相关内容

  • 没有找到相关文章

最新更新