在 Swift 中扩展泛型整数类型

Extending Generic Integer Types in Swift

所以我试图用我经常使用的一些方便的函数来扩展 Swift 的整数类型,但是我不清楚我应该扩展哪些协议。

举个例子,假设我想实现一个函数来限制一个值(如果它小于最小值,则将其设置为该值,否则如果它大于最大值,则将其设置为该值)。我的第一个想法是做这样的事情:

extension Int {
    func clamp(minimum:Int, maximum:Int) {
        if self < minimum { return minimum }
        if self > maximum { return maximum }
        return self
    }
}

一个简单的例子,但它说明了问题;如果我现在想为 UInt 调用它,那么我当然不能,所以我必须添加一个等价于 UInt 的东西,但这对 UInt16 不起作用,所以-on.

我想我也许可以在链上扩展一些东西,并改用泛型,但是 IntegerType 等协议似乎无法扩展。

那么,有没有更合适的地方可以放置我的分机?

你走在正确的轨道上。其实你说的是面向协议编程。

Protocol extensions: Swift is very focused on protocol-oriented development — there’s even a session on the topic at WWDC 2015. Swift 2.0 adds protocol extensions, and the standard library itself uses them extensively. Where you used to use global functions, Swift 2.0 now adds methods to common types so functions chain naturally, and your code is much more readable.

https://developer.apple.com/swift/blog/?id=29

事实上 Swift 2.0 的一大特点是它允许您向协议添加方法,因此您可以将 clamp 添加到 IntegerType

视频很好地解释了 Protocol Oriented Programming 的主题:https://developer.apple.com/videos/wwdc/2015/?id=408

您只需要升级到 Swift 2.0.

虽然 Swift 2.0 仍处于测试阶段,但我建议您添加如图所示的扩展。您必须为 IntInt64 等复制粘贴相同的代码,但目前没有其他方法可以执行您想要的操作。

一旦 Swift 2.0 发布,您就可以做到这一点

extension IntegerType {
    mutating func clamp(minimum:Self, maximum:Self) {
        if self < minimum { self = minimum }
        if self > maximum { self = maximum }
    }
}

如果您可以等到 9 月份的某个时间发布您的应用程序,那么我鼓励您立即开始使用 Swift 2.0。

更新

使用 Swift 2.0,您还可以向 Comparable 协议添加扩展,这将确保 clamp() 可用于其他类型,例如 DoubleFloat,等

extension Comparable {
    mutating func clamp(minimum:Self, maximum:Self) {
        if self < minimum { self = minimum }
        if self > maximum { self = maximum }
    }
}

对于 Swift 2,请参阅 Andriy Gordiychuk 的回答,这将是正确的。如果你需要 Swift 1,那么这不能用扩展来完成,必须用自由函数来完成。这就是为什么 stdlib 中有那么多自由函数在 Swift 2.

中成为扩展的原因

对于Swift1,你要做的是:

func clamp<T:Comparable>(value: T, #minimum:T, #maximum:T) -> T {
    if value < minimum { return minimum }
    if value > maximum { return maximum }
    return value
}

如果您更喜欢修改值(如 Andriy 的示例所做的那样),您可以这样做:

func clamp<T:Comparable>(inout value: T, #minimum:T, #maximum:T) {
    if value < minimum { value = minimum }
    else if value > maximum { value = maximum }
}

否则你必须为每个类型写一个扩展。这是 Swift 1 中唯一的其他答案。Swift 2 好多了。

extension Comparable {
    func clamp(var minimum: Self, var _ maximum: Self) -> Self {
        if maximum < minimum { swap(&maximum, &minimum) }
        if self < minimum { return minimum }
        if self > maximum { return maximum }
        return self
    }
}

例如,这里是 clamped 的整数实现,它也普遍适用于任何可以使用它的东西:

extension Comparable
{
    func clamped(from lowerBound: Self, to upperBound: Self) -> Self {
        return min(max(self, lowerBound), upperBound)
    }

    func clamped(to range: ClosedRange<Self>) -> Self {
        return min(max(self, range.lowerBound), range.upperBound)
    }
}

extension Strideable where Self.Stride: SignedInteger
{
    func clamped(to range: CountableClosedRange<Self>) -> Self {
        return min(max(self, range.lowerBound), range.upperBound)
    }
}

和测试用例:

7.clamped(from: 3, to: 6)   // 6

7.clamped(to: 3 ... 6)      // 6
7.clamped(to: 3 ... 7)      // 7
7.clamped(to: 3 ... 8)      // 7

7.0.clamped(to: 3.0 ... 6.0)  // 6
7.0.clamped(to: 3.0 ... 7.0)  // 7
7.0.clamped(to: 3.0 ... 8.0)  // 7