2

I want to define a function every which takes in an iterator and while it's not None, makes sure that all values are true.

Example applications:

every([true, true, true].into_iter()) == true
every([true, false, true].into_iter()) == false

I've had trouble getting it to work just with a Vec, let alone an Iterator. I've tried the following and a few variations but haven't gotten anywhere.

use std::ops;

fn every<T>(v: Vec<T>) -> bool
where
    T: ops::Not,
{
    for item in v {
        match !item {
            T::No => return false,
        }
    }
    true
}

This code gets the error:

error[E0599]: no associated item named `No` found for type `T` in the current scope
 --> src/lib.rs:9:13
  |
9 |             T::No => return false,
  |             ^^^^^ associated item not found in `T`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
z.f.s
  • 45
  • 6
  • 2
    You could use [`Iterator::all`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all) – hellow Dec 29 '18 at 09:57
  • 1
    [exemple](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ee49af6daf752d20f3804586ce83b98e), be aware that here you are not using an iterator, see [all()](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all). – Stargateur Dec 29 '18 at 10:03

1 Answers1

3

A more generic example based on Stargateur's comment

fn every<T, I>(v: I) -> bool
where
    I: IntoIterator<Item = T>,
    T: std::ops::Not<Output = bool>,
{
    v.into_iter().all(|x| !!x)
}

(playground)

v can be anything that implements IntoIterator, e.g. a Vec, but also something like map, or filter, which makes this solution very generic.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hellow
  • 12,430
  • 7
  • 56
  • 79
  • Would it be possible to cast `x` to a bool instead of using `!!`. I tried `x as bool` and `bool::from(x)` but they both did not work. – z.f.s Dec 29 '18 at 11:56
  • I took the compilers suggestion and used the trait `bool: std::convert::From instead of std::ops::Not`. This allowed me to use `x.into()` instead of double negation. Both seem to work for my particular project, I wouldn't know which is the superior method in this case, or if they are equivalent. – z.f.s Dec 29 '18 at 12:04
  • 3
    @z.f.s `!!x` is an idiom from C where it is useful for turning a truthy integer into a real `true` or `false` (which are just 1 and 0 if you look closely). Rust doesn't have "truthiness" (`!` on integers does a bitwise NOT), so I wouldn't use it here. In fact I would not make T generic at all if you only intend to use `every` on `bool`-containing iterators, but I might choose `T: Borrow` to abstract over references if desired. – trent Dec 29 '18 at 13:19
  • Related: [How can I add new methods to Iterator?](https://stackoverflow.com/q/30540766/155423) – Shepmaster Dec 29 '18 at 23:58
  • 1
    It's not super idiomatic to define two generic types [when one will do](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9ea37bc8f960cf1e83d8e92b676e516a) – Shepmaster Dec 29 '18 at 23:59