How to write a limit function in Scala?
After wondering about certain bugs in my first Scala application, I discovered that my limit function was not quite working ... at all!
So here was my first attempt:
def limit(x : Double, min: Double, max : Double) = {
if (x < min) min;
if (x > max) max;
x;
}
It always returned x
!
My second attempt looked like this:
def limit(x : Double, min: Double, max : Double) : Double = {
if (x < min) 开发者_Python百科return min;
if (x > max) return max;
x;
}
and it worked.
So my question: why are min;
and max;
from the first example basically no-ops, and x;
is not?
And is my second attempt good Scala?
Or even:
val limited = lower max x min upper
max
and min
have the same precedence and associate left, so no parens are needed
I've written a generic version of this (which I had called clamp
), which looks like this:
// NOTE: This will still do some boxing and unboxing because Ordering / Ordered is not @specialized.
@inline def clamp[@specialized(Int, Double) T : Ordering](value: T, low: T, high: T): T = {
import Ordered._
if (value < low) low else if (value > high) high else value
}
In Scala, the result of an expression is the last value mentioned in that expression. The result of the if-expressions in your first attempt is thrown away, because each if-expression is followed by another expression. Your second attempt is ok but you could do it with if ... else
like in my example. You could write yours like this:
def limit(x: Double, min: Double, max: Double): Double =
if (x < min) min else if (x > max) max else x
If you don't specify return
explicitly, then return value is the result of the last expression. In your first example your last expression is x;
, so it would be returned in any case. If you want to return different value, then you can use if/else if/else
:
def limit(x : Double, min: Double, max : Double) =
if (x < min) min
else if (x > max) max
else x
In this case if/else if/else
is treated as single expression that returns single value.
You can also use pattern matching like this (it's also single expression):
def limit(x : Double, min: Double, max : Double) = x match {
case x if x < min => min
case x if x > max => max
case _ => x
}
I don't think that your second example can be described as "good scala". In such simple case it just complicates the whole thing and has 3 points of return (instead of single point of return). It also adds more unnecessary boilerplate.
Why not just:
import math.{min, max}
val limited = min(max(lower, x), upper)
or
val limited = (lower max x) min upper
精彩评论