在Swift中扩展泛型整数类型
所以我尝试用一些我经常使用的方便函数来扩展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
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