类似于Equatable的Swift协议

时间:2015-04-28 22:01:21

标签: cocoa swift swift-protocols

我正在尝试为Lerp-able(线性插值)类型创建协议。我声明它与Equatable的定义方式类似:

protocol Lerpable {
    func lerp(from: Self, to: Self, alpha: Double) -> Self
}

不幸的是,当我尝试为Lerpable实施Double时:

func lerp(from: Double, to: Double, alpha: Double) -> Double {
    return from + alpha * (to - from)
}
extension Double: Lerpable {}

我收到错误:Type 'Double' does not conform to protocol 'Lerpable'

我认为这会非常简单,但也许我只是不明白Equatable的工作原理。或者它是Swift中的特例?有什么想法吗?

更新:正确的答案是below,这是代码的最终版本,供其他人参考:

protocol Lerpable {
    func lerp(to: Self, alpha: Double) -> Self
}

extension Double: Lerpable {
    func lerp(to: Double, alpha: Double) -> Double {
        return self + alpha * (to - self)
    }
}

func lerp<T: Lerpable>(from: T, to: T, alpha: Double) -> T {
    return from.lerp(to, alpha: alpha)
}

我添加了全局lerp功能,所以我仍然可以将其称为
lerp(foo, bar, alpha: 0.5)
而不是 foo.lerp(bar, alpha: 0.5)

2 个答案:

答案 0 :(得分:5)

要解决您的问题,您需要将lerp功能放在extension内,如下所示:

extension Double: Lerpable {
    func lerp(from: Double, to: Double, alpha: Double) -> Double {
        return from + alpha * (to - from)
    }
}

如果您查看Equatable protocol

protocol Equatable {
    func == (lhs: Self, rhs: Self) -> Bool
}

您在类型==之外声明其方法(extension)的原因是Equatable要求您重载运算符,运算符必须在全球范围内。这是一个澄清的例子:

protocol MyProtocol {
    func *** (lhs: Self, rhs: Self) -> Self
}

现在让Int采用协议:

extension Int : MyProtocol {}

infix operator *** {}
func *** (lhs: Int, rhs: Int) -> Int {
    return lhs * rhs
}

答案 1 :(得分:0)

您可以通过为进度值“t”

添加类型来进一步抽象实现
public protocol Lerpable {
    typealias LerpProgressType
    func lerpTo(value: Self, t: LerpProgressType) -> Self
}
public func lerp<T:Lerpable>(from: T, _ to: T, _ t: T.LerpProgressType) -> T {
    return from.lerpTo(to, t: t)
}

// implementations
extension Double : Lerpable {
    public typealias LerpProgressType = Double
    public func lerpTo(value: Double, t: Double) -> Double {
        return (1.0 - t) * self + t * value
    }
}
extension Float : Lerpable {
    public typealias LerpProgressType = Float
    public func lerpTo(value: Float, t: Float) -> Float {
        return (1.0 - t) * self + t * value
    }
}
extension CGFloat : Lerpable {
    public typealias LerpProgressType = CGFloat
    public func lerpTo(value: CGFloat, t: CGFloat) -> CGFloat {
        return (1.0 - t) * self + t * value
    }
}

您现在还可以扩展各种结构(例如CGPoint,CGSize,CGRect,CATransform3D等):

extension CGPoint : Lerpable {
    public typealias LerpProgressType = CGFloat
    public func lerpTo(value: CGPoint, t: CGFloat) -> CGPoint {
        return
            CGPoint(
                x: x.lerpTo(value.x, t),
                y: y.lerpTo(value.y, t)
            )
    }
}
extension CLLocationCoordinate2D : LinearInterpolation {
    public typealias LerpProgressType = CLLocationDegrees
    public func lerpTo(value: CLLocationCoordinate2D, t: CLLocationDegrees) -> CLLocationCoordinate2D {
        return
            CLLocationCoordinate2D(
                latitude:  latitude.lerpTo(value.latitude, t),
                longitude: longitude.lerpTo(value.longitude, t)
            )
    }
}

在通用结构中实现线性插值:

public struct ValueRange<T> {
    public var start:T
    public var end:T
}

extension ValueRange where T:Lerpable {
    public func lerp(t: T.LerpProgressType) -> T {
        return start.lerpTo(end, t: t)
    }
}