AManOfScience
AManOfScience

Reputation: 1183

How should providing a one or zero be done now that num::Zero and One are deprecated?

In writing my own generic sigma summation function to get practice with Rust, I've hit an issue with providing a seed value of zero as the accumulator.

fn sigma<I, T, F>(iter: I, func: F) -> T
    where I: Iterator<Item=T>,
          T: Add<Output=T>,
          F: Fn(T) -> T
{
    iter.fold(0, |acc, x| acc + func(x))
}

Playground Link

I understand that it's wrong, as 0 is a concrete type, and thus not T. Other answers (like this and this one) rely on constructs like Int::zero, which are deprecated as of 1.11.

There are other ways of doing this, but I am particularly interested in how it should be done, as testing for one, zero, or negativity is a common operation in numeric procedures that I'll hit again soon enough. Plus, now I'm curious.

My Rust version is 1.16.

Upvotes: 1

Views: 146

Answers (1)

E_net4
E_net4

Reputation: 30042

Asking for how your function should be done can become opinion-based: there are multiple good ways of achieving this. Nevertheless, it is answerable if we narrow down to these two approaches, which I would consider typical and idiomatic:


Zero and One were deprecated (never even stabilized, in fact!) from the standard library mostly because there is a more generalized means of making products and sums from iterators: the Sum and Product traits are relied upon by iterators when calling methods sum() and product(), and can even yield a result of a type other than the items'.

use std::iter::{Iterator, Sum};

fn sigma<I, T, F>(iter: I, func: F) -> T
    where I: Iterator<Item = T>,
          T: Sum,
          F: Fn(T) -> T
{

    iter.map(func).sum::<T>()
}

Playground. I took the liberty of moving the element transformation to a map in the iterator definition chain, thus enabling the use of sum() as a terminal operation.


The trait Zero and One are still available in crate num (or num-traits), so you can use that instead.

extern crate num;

use std::ops::Add;
use std::iter::Iterator;
use num::Zero;

fn sigma<I, T, F>(iter: I, func: F) -> T
    where I: Iterator<Item = T>,
          T: Zero + Add<Output = T>,
          F: Fn(T) -> T
{
    iter.map(func).fold(T::zero(), |a, b| a + b)
}

Playground

Upvotes: 4

Related Questions