Swift - 如何声明一个接收范围内数字的方法

Swift - how to declare a method which receives a number in a range

我想创建一个函数,其数字参数应介于 0..100 %

我认为执行此操作的最佳方法是使用 FloatingPointType 协议创建包装器类型,但我收到编译错误

Protocol 'FloatingPointType' can only be used as a generic constraint because it has Self or associated type requirements

struct Percent {
    init(val : FloatingPointType) {
        // enforce value is between 0..100
    }
}


func hideView(percent : Percent) {
  // percent is 0..100 at this point
.. do some work here
}

在编译时强制执行此条件的正确方法是什么?

更新:Swift 5.1 开始,使用 NSHipster 上的 “property wrappers”, see for example “Implementing a value clamping property wrapper” 可以更轻松地实现这一点。

最简单的方法是定义一个包含 Double(或FloatInt)在要求范围内:

struct P {
    let val : Double
    init (val : Double) {
        // ...
    }
}

但是如果你想处理不同的浮点类型那么 你必须定义一个通用的 class

struct Percent<T : FloatingPointType> {
    let val : T
    init(val : T) {
       self.val = val
    }
}

要比较您需要的值,还需要 Equatable

struct Percent<T : FloatingPointType where T: Equatable> {
    let val : T
    init(val : T) {
        if val < T(0) {
            self.val = T(0)
        } else if val > T(100) {
            self.val = T(100)
        } else {
            self.val = val
        }
    }
}

示例:

let p = Percent(val: 123.4)
println(p.val) // 100.0

请注意,这要求 hideView() 也是通用的:

func hideView<T>(percent : Percent<T>) {
    // percent.val has the type `T` and is in the range
    // T(0) ... T(100)
}

这听起来像是您试图在编译时强制执行,即您不能将 0.0 到 100.0 范围之外的值传递给函数。你不能那样做。

你可以做的是编写你的函数以在传递给超出范围的值时抛出异常,或者向用户显示错误并且 return 如果它超出范围。

您正在寻找的语言功能称为偏函数。部分函数是未为指定类型的所有可能参数定义的函数。例如,它们在 Haskell 或 Scala 中可用 - 但它们在 Swift.

中不可用

因此,您最好的办法是在运行时检查提供的值是否在有效范围内并采取相应措施(例如引发异常或 return 错误)。

加起来 并更新 Swift 5:

struct Percentage<T: FloatingPoint> {
  let value: T
  init(value: T) {
    self.value = min(max(value, T(0)), T(100))
  } 
}

Usage site,你可以这样定义泛型类型:

func updateCircleWith(percentage: Percentage<CGFloat>) {
  // percentage.value will be between 0 and 100 here
  // of course the CGFloat(0) and CGFloat(100)
}