[英]Why does the compiler not see the default code in a protocol?
编辑:我已经重申并希望在这里澄清这个问题。 现在我已经添加了解决方案。
我已经为采用我的protocol
的struct
定义了一个 function (参见附件示例中的foo()
)作为默认 function 。 它应用了针对其他两个变量定义的+
运算符,这些变量本身采用其他protocols
,并且+
在其中一个协议中定义。 变量使用associatedtype
进行类型化。 我收到消息:
二元运算符“+”不能应用于“Self.PointType”和“Self.VectorType”类型的操作数
如果我在我的struct
中实现 function (参见附件中的 bar() )它可以工作,所以我确信我的 + 运算符可以工作。 我的例子被缩减到在操场上工作所需的最低限度。 只需删除LineProtocol extension
中的注释即可得到错误。 在我看来, Self.PointType
是一个Point
和Self.VectorType
是一个Vector
。
需要明确的是:我使用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), 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,您可以摆脱对您的 associatedtype 要求的显式一致性,并让编译器推断出1符合您的 associatedtypes 要求并这样编写您的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)
}
}
由于 Swift 的类型推断,您实际上不需要将 Int 的具体 Item 声明为 IntStack 定义的一部分。 因为 IntStack 符合 Container 协议的所有要求,Swift 可以通过查看 append(_:) 方法的 item 参数的类型和下标的返回类型来推断合适的 Item 使用。 事实上,如果你从上面的代码中删除 typealias Item = Int 行,一切仍然有效,因为很清楚应该为 Item 使用什么类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.