简体   繁体   English

在 Swift 中扩展泛型整数类型

[英]Extending Generic Integer Types in Swift

So I'm trying to extend Swift's integer types with a few convenient functions that I use a lot, however I'm not clear on which protocols I should be extending.所以我试图用一些我经常使用的方便的函数来扩展 Swift 的整数类型,但是我不清楚我应该扩展哪些协议。

As an example, let's say I want to implement a function for clamping a value (if it's less than a minimum set it to that, otherwise if it's greater than a maximum then set it to that instead).例如,假设我想实现一个用于钳位值的函数(如果它小于最小值,则将其设置为该值,否则,如果它大于最大值,则将其设置为该值)。 My first thought was to do something like this:我的第一个想法是做这样的事情:

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

Bit of a simplistic example, but it illustrates the problem;一个简单的例子,但它说明了问题; if I want to now call this for a UInt then naturally I can't, so I have to add an equivalent to UInt , but that won't work for a UInt16 and so-on.如果我现在想为UInt调用它,那么自然我不能,所以我必须添加一个等效于UInt ,但这不适用于UInt16等等。

I thought that I could perhaps extend something higher up the chain, and use generics instead, however protocols such as IntegerType can't seem to be extended.我想我也许可以将一些东西扩展到链上,并使用泛型代替,但是诸如IntegerType协议似乎无法扩展。

So, is there somewhere more appropriate that I could put my extension(s)?那么,有没有更合适的地方可以放置我的扩展程序?

For Swift 2, see Andriy Gordiychuk's answer, which will be correct then.对于 Swift 2,请参阅 Andriy Gordiychuk 的答案,那时该答案是正确的。 If you require Swift 1, then this cannot be done with extensions, and must be done with free functions.如果您需要 Swift 1,那么这不能通过扩展来完成,而必须使用自由函数来完成。 This is why there are so many free functions in stdlib that became extensions in Swift 2.这就是为什么 stdlib 中有这么多免费函数在 Swift 2 中成为扩展的原因。

For Swift 1, what you have to do is:对于 Swift 1,您需要做的是:

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

If you prefer modifying the value (as Andriy's example does), you can do it this way:如果您更喜欢修改值(如 Andriy 的示例所做的那样),您可以这样做:

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

Otherwise you have to write an extension on every type.否则,您必须为每种类型编写扩展。 It's the only other answer in Swift 1. Swift 2 is much better.这是 Swift 1 中唯一的其他答案。Swift 2 要好得多。

While Swift 2.0 is still in beta I suggest you to add extensions like you illustrated.虽然 Swift 2.0 仍处于测试阶段,但我建议您添加像您说明的那样的扩展。 You will have to copy-paste the same code for Int , Int64 etc, but there is no other way to do what you want at the moment.您必须为IntInt64等复制粘贴相同的代码,但目前没有其他方法可以执行您想要的操作。

Once Swift 2.0 is out you will be able to do this Swift 2.0 发布后,您将能够执行此操作

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

If you can wait with the release of your app until some time in September then I encourage you to start using Swift 2.0 right now.如果您可以等到 9 月某个时候发布您的应用程序,那么我鼓励您立即开始使用 Swift 2.0。

Update更新

With Swift 2.0 you can also add extension to Comparable protocol which will ensure that clamp() is available for other types such as Double , Float , etc使用 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 }
    }
}

By way of example, here is an integer implementation of clamped that also applies generically to anything that can use it:举例来说,这里是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)
    }
}

And the test cases:和测试用例:

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

You are on the right track.你走在正确的轨道上。 In fact you are talking about Protocol Oriented Programming.事实上,您正在谈论面向协议的编程。

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.协议扩展: Swift 非常专注于面向协议的开发——在 WWDC 2015 上甚至有一个关于这个主题的会议。Swift 2.0 添加了协议扩展,标准库本身也广泛使用它们。 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.在过去使用全局函数的地方,Swift 2.0 现在为通用类型添加了方法,因此函数可以自然链接,并且您的代码更具可读性。

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

In fact a big feature of Swift 2.0 is that it allows you to add methods to protocols so you can add clamp to IntegerType .事实上,Swift 2.0 的一个重要特性是它允许您向协议添加方法,以便您可以向IntegerType添加clamp

The video explains very well the topic of Protocol Oriented Programming : https://developer.apple.com/videos/wwdc/2015/?id=408该视频很好地解释了Protocol Oriented Programming主题: https : //developer.apple.com/videos/wwdc/2015/?id=408

You just need to upgrade to Swift 2.0.您只需要升级到 Swift 2.0。

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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM