Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Swift中扩展泛型整数类型_Swift_Swift2_Protocols_Protocol Extension_Clamp - Fatal编程技术网

在Swift中扩展泛型整数类型

在Swift中扩展泛型整数类型,swift,swift2,protocols,protocol-extension,clamp,Swift,Swift2,Protocols,Protocol Extension,Clamp,所以我尝试用一些我经常使用的方便函数来扩展Swift的整数类型,但是我不清楚应该扩展哪些协议 举个例子,假设我想实现一个钳制值的函数(如果小于最小值,则将其设置为该值,否则如果大于最大值,则将其设置为该值)。我的第一个想法是这样做: extension Int { func clamp(minimum:Int, maximum:Int) { if self < minimum { return minimum } if self > maxim

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

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

extension Int {
    func clamp(minimum:Int, maximum:Int) {
        if self < minimum { return minimum }
        if self > maximum { return maximum }
        return self
    }
}
extension Int{
函数钳位(最小值:Int,最大值:Int){
如果自<最小值{返回最小值}
如果自>最大值{返回最大值}
回归自我
}
}
有点简单化,但它说明了问题;如果我现在想为
UInt
调用它,那么我当然不能,所以我必须添加一个等价于
UInt
,但这对
UInt16
不起作用,等等

我想我也许可以扩展链的更高层,使用泛型,但是像
IntegerType
这样的协议似乎无法扩展


那么,有没有更适合我的分机呢?

你走对了方向。事实上,您正在谈论面向协议的编程

协议扩展:Swift非常注重面向协议的扩展 发展——2015年世界野生动植物保护大会上甚至有一个关于这个主题的会议。敏捷的 2.0添加了协议扩展,标准库本身也广泛使用它们。以前使用全局函数的地方,Swift 2.0 现在将方法添加到常见类型中,使函数自然链接,并且 您的代码更具可读性

事实上,Swift 2.0的一大特点是它允许您向协议中添加方法,以便您可以将
钳制
添加到
整型

视频很好地解释了面向协议编程的主题:


您只需升级到Swift 2.0。

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

一旦Swift 2.0发布,您将能够做到这一点

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

有关Swift 2,请参见安德烈·戈尔迪丘克的答案,该答案将是正确的。如果您需要Swift 1,那么这不能通过扩展来完成,必须通过自由函数来完成。这就是为什么stdlib中有如此多的免费函数成为swift2的扩展

对于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钳位(值:T,#最小值:T,#最大值:T)->T{
如果值<最小值{返回最小值}
如果值>最大值{返回最大值}
返回值
}
如果您喜欢修改该值(如Andrey的示例所示),可以通过以下方式进行:

func clamp<T:Comparable>(inout value: T, #minimum:T, #maximum:T) {
    if value < minimum { value = minimum }
    else if value > maximum { value = maximum }
}
func钳位(输入值:T,#最小值:T,#最大值:T){
如果值<最小值{value=minimum}
如果值>最大值{值=最大值}
}
否则,您必须在每个类型上编写扩展。这是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
    }
}
功能钳位(最小值:自,最大值:自)->Self{ 如果最大值<最小值{swap(&最大值,&最小值)} 如果自<最小值{返回最小值} 如果自>最大值{返回最大值} 回归自我 } }
举例来说,这里是一个
钳制的
的整数实现,它一般也适用于任何可以使用它的东西:

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

与其扩展每个人都熟悉的类型,不如用自己的类包装整数,或者将常用的方法放在静态math util classIsn扩展中,而不是专门用作此扩展的替代方法?我认为我可以使用泛型将我的函数放入到say
IntegerType
的扩展中,这样它就会出现在所有整数值中。对我来说,这似乎比一个包含大量静态函数的IntUtils类要整洁得多。不这样做的理由是,对于低级类型,有一个众所周知的接口,所有使用特定语言的程序员都会知道。如果我知道在一个项目中可以用一个整数做什么,我就应该知道在另一个项目中可以用一个整数做什么。@bhspencer:我看不出有什么问题。如果您更改了项目并且错过了一些扩展。。。只需将它们导入到新版本中即可!:-)扩展是iOS开发的重要组成部分。在Swift之前,在Objective-C中,它们被称为类别。请先阅读官方文件,然后再建议不要使用它们。。。你会发现很多情况下,这种技术非常有用。@appzyorlife我认为问题的根源在于扩展低级类型违反了“关注点分离”的原则。整数应该只关注与整数相关的事情。您可以在Swift中扩展Integer,以添加特定于您的问题域的函数,例如,如果您的域是网球,您可以使用添加15或10分的函数扩展Integer,以帮助保持分数。在这种情况下,更好的解决方案是使用TennisScore类包装整数,而不是扩展整数。请注意,对于给定的示例,
clamp
返回值而不是变异,这最好应用于
Compariable
而不是
IntegerType
。这是正确的,但原始函数并没有声明返回类型(尽管它的主体中确实包含“return”)。因此,我假设1)@Haravik只想扩展integer类型(似乎是这样),2)出于这个目的,更容易使用.clamp()而不是a=a.clamp(),不管它是否返回也无关紧要。即使在你的版本中,它仍然可以比较。我现在已经将@RobNapier的答案标记为正确,但听起来Swift 2的更改更符合我的需要。而且,我的
钳夹
功能就像一个快速而肮脏的例子
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