I find it always pays to be tidy and conscientious about spacing. Here, I'd add spaces after the :
in the argument declaration
// fn sum_square_largest(x:f64, y:f64, z:f64) -> f64 {
fn sum_square_largest(x: f64, y: f64, z: f64) -> f64 {
Next, I'd wrap the where
clause onto the next line. where
clauses often get large, so I find it best to let them have breathing room, and only put one type per line:
// fn partial_min_three<T>(v1: T, v2: T, v3: T) -> Option<T> where T: PartialOrd<T> {
fn partial_min_three<T>(v1: T, v2: T, v3: T) -> Option<T>
where T: PartialOrd<T>
{
Checking for Some
or None
and doing something is a common pattern. In this case, you can use Option::and_then
:
// match partial_min(v2, v3) {
// Some(x) => partial_min(v1, x),
// None => None
// }
partial_min(v2, v3).and_then(|x| partial_min(v1, x))
Programming is often about clarity in expressing your intentions, and I doubt that the majority of programmers immediately know what 0 / 0
is for floating point numbers. You should be explicit:
// None => 0.0_f64/0.0_f64
None => std::f64::NAN,
Again, we can use existing patterns to deal with checking for Some
/ None
. This time, we can use Option::map
:
// match partial_min_three(x, y, z) {
// Some(a) => x * x + y * y + z * z - a * a,
// None => std::f64::NAN,
// }
partial_min_three(x, y, z)
.map(|a| x * x + y * y + z * z - a * a)
.unwrap_or(std::f64::NAN)
I disagree with your choice of NaN as a magic value. Magic values drive me crazy, and Rust has great choices for avoiding them - Option
and Result
!
fn sum_square_largest(x: f64, y: f64, z: f64) -> Option<f64> {
partial_min_three(x, y, z)
.map(|a| x * x + y * y + z * z - a * a)
}
I'd probably create a tiny function for squaring. It's likely to get inlined, so I'm not worried about performance, just readability:
.map(|a| square(x) + square(y) + square(z) - square(a))
All together (playpen):
fn sum_square_largest(x: f64, y: f64, z: f64) -> Option<f64> {
partial_min_three(x, y, z)
.map(|a| square(x) + square(y) + square(z) - square(a))
}
fn partial_min_three<T>(v1: T, v2: T, v3: T) -> Option<T>
where T: PartialOrd<T>
{
partial_min(v2, v3).and_then(|x| partial_min(v1, x))
}
fn square(x: f64) -> f64 { x * x }
// Copied from the standard library as it is currently unstable
// and the beta doesn't allow unstable features
use std::cmp::Ordering;
fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
match v1.partial_cmp(&v2) {
Some(Ordering::Less) | Some(Ordering::Equal) => Some(v1),
Some(Ordering::Greater) => Some(v2),
None => None
}
}
fn main() {
let z = sum_square_largest(1.0, 2.0, 3.0);
println!("{:?}", z);
}