在Swift中扩展通用整数类型

10

所以我在尝试使用一些方便的函数扩展Swift整数类型,但我不确定应该扩展哪些协议。

比如说,假设我想实现一个函数来限制一个值的范围(如果它小于最小值就将其设置为最小值,否则如果它大于最大值,则将其设置为最大值)。我的第一个想法是这样的:

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

这只是一个简单的示例,但它说明了一个问题;如果我现在想要调用这个函数来处理 UInt,那么自然而然地,我不能这样做,所以我必须添加一个等效于 UInt 的函数,但这对于 UInt16 等类型就不再适用。

我曾尝试过扩展更高层次的东西,使用泛型,但是似乎无法扩展像 IntegerType 这样的协议。

所以,是否有更合适的地方可以放置我的扩展呢?


1
不要扩展每个人都已经熟悉的类型,而应该用自己的类包装整数或将常用方法放在静态数学工具类中。 - bhspencer
2
扩展不是专门作为这个的替代品吗?我认为我可以使用泛型将我的函数放入IntegerType的扩展中,这样它就会出现在所有整数值中。对我来说,这似乎比一个拥有大量静态函数的IntUtils类更加整洁。 - Haravikk
1
不这样做的理由是,特定语言中所有程序员都将知道低级类型的已知接口。如果我知道在一个项目中可以使用整数来做什么,那么我应该知道在另一个项目中可以使用整数来做什么。 - bhspencer
1
@bhspencer:我不认为有什么问题。如果你更改了项目并且错过了一些扩展...只需将它们导入到新项目中即可! :-) 扩展是iOS开发的重要组成部分。在Swift之前,在Objective-C中,它们被称为类别。在建议不使用它们之前,请先阅读官方文档...您会发现许多情况下这种技术非常有用。 - Luca Angeletti
1
还有一个额外的问题是API可发现性,bhspencer也提到了这一点。如果您对应用程序域进行建模,则每个模型的方法都很容易被发现。如果您使用扩展名,那么您的协作者如何知道要使用Int.clamp? - Ilias Karim
显示剩余6条评论
5个回答

8

如果你需要适用于Swift 2的翻译,请查看Andriy Gordiychuk的答案,那时它是正确的。 如果你需要适用于Swift 1,则无法使用扩展完成,必须使用自由函数进行操作。 这就是为什么在Swift 2中有很多stdlib中的自由函数变成扩展的原因。

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

如果你更喜欢修改值(像安德烈的例子一样),可以按照以下方式进行:
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要好得多。

看起来现在这是正确的答案;幸运的是我没有时间压力,所以我现在可以将就一下,等到Swift 2出现时再回头看看,感谢你的答案! - Haravikk

5

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

如果你可以等到九月份再发布你的应用程序,我鼓励你立即开始使用 Swift 2.0。

更新

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

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

请注意,对于给定的示例,如果clamp返回一个值而不是进行变异,则最好应用于Comparable而不是IntegerType - Rob Napier
没错,但原始函数没有声明返回类型(尽管它在其主体中包含“return”)。因此,我假设1)@Haravikk只想扩展整数类型(这似乎是情况),并且2)为了这个目的,使用a.clamp()比a = a.clamp()更容易。 - Andriy Gordiychuk
转念一想,它是否返回并不重要。即使在您的版本中,它仍然可以是可比较的。 - Rob Napier
我暂时将@RobNapier的答案标记为正确,但听起来Swift 2的更改更符合我的需求。此外,我的“clamp”函数只是一个快速而肮脏的示例,非常感谢您坚持不懈地使用它,但是,您绝对正确,这可能是“Comparable”的更好示例! - Haravikk

2
举个例子,这里是一个整数实现的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

1
你正在走上正确的道路。实际上,你正在谈论协议导向编程。
协议扩展:Swift非常注重协议导向开发--甚至在WWDC 2015上有一个关于该主题的会话。Swift 2.0添加了协议扩展,并且标准库本身广泛使用它们。在以前使用全局函数的地方,Swift 2.0现在将方法添加到常见类型中,因此函数链自然,您的代码更加可读。 https://developer.apple.com/swift/blog/?id=29 事实上,Swift 2.0的一个重要特性是允许您向协议添加方法,因此您可以将clamp添加到IntegerType中。
这个视频很好地解释了“协议导向编程”的主题:https://developer.apple.com/videos/wwdc/2015/?id=408 你只需要升级到Swift 2.0即可。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接