How may I implement a method on a core object type like Vector?


#1

Here’s the test I would like to pass.

#[test]
fn it_implements_individual_uniq_on_vec() {
  assert_eq!(
    vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] ),
    vec![3,4,6]
  );
} 

So I’m writing my own uniq method. I’ve got a working method, but I don’t know how to add the uniq method globally to all Vectors.

I’m not worried about the unique implementation itself… just making it available after use. The outline of the method I’ve got so far:

pub trait Uniq<T>{
  fn uniq(&self, other: Vec<T>) -> Self;
} 

impl<T: Clone + Iterator + PartialEq> Uniq<T> for Vec<T> {
  fn uniq(&self, other: Vec<T>) -> Vec<T> {
    // I have code here
  }
}

After including my crate in my integration test file and then having use mylib::*; I still get this error.

error: no method named `uniq` found for type `collections::vec::Vec<_>` in the current scope
assert_eq!(vec![1,2,3,4,5,6].uniq(vec![1,2,5,7,9]),vec![3,4,6]);

I haven’t mastered use of traits and impl yet so I would greatly appreciate your help on this one.


#2

Following the example from Reference#derive I’ve rewritten the code as follows. I’m getting the same error.

pub trait Uniq{
  fn uniq(&self, other: Self) -> Self;
}

impl<T: Clone + Iterator + PartialEq + Uniq> Uniq for Vec<T> {
  fn uniq(&self, other: Vec<T>) -> Vec<T> {
    // code is here
  }
}

#3

So, here’s a complete testable example:

==> src/lib.rs <==
pub trait Uniq<T>{
  fn uniq(&self, other: Vec<T>) -> Self;
}

impl<T: Clone + Iterator + PartialEq> Uniq<T> for Vec<T> {
  fn uniq(&self, _other: Vec<T>) -> Vec<T> {
    unimplemented!()
  }
}

==> tests/foo.rs <==
extern crate foo;
use foo::*;

#[test]
fn it_implements_individual_uniq_on_vec() {
  assert_eq!(
    vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] ),
    vec![3,4,6]
  );
}

==> Cargo.toml <==
[package]
name = "foo"
version = "0.1.0"

Running this gives the following error:

   Compiling foo v0.1.0 (.../foo)
tests/foo.rs:7:23: 7:46 error: no method named `uniq` found for type `collections::vec::Vec<_>` in the current scope
tests/foo.rs:7     vec![1,2,3,4,5,6].uniq( vec![1,2,5,7,9] ),
                                     ^~~~~~~~~~~~~~~~~~~~~~~
<std macros>:1:1: 9:39 note: in expansion of assert_eq!
tests/foo.rs:6:3: 9:5 note: expansion site
tests/foo.rs:7:23: 7:46 note: the method `uniq` exists but the following trait bounds were not satisfied: `_ : core::iter::Iterator`
<std macros>:5:8: 5:18 error: the type of this value must be known in this context
...

It’s a little confusing because of the Vec<_>. This is because the digits could be digits of any type. Trying again with a concrete type:

==> tests/foo.rs <==
extern crate foo;
use foo::*;

#[test]
fn it_implements_individual_uniq_on_vec() {
  assert_eq!(
    vec![1u8,2,3,4,5,6].uniq( vec![1,2,5,7,9] ),
    vec![3,4,6]
  );
}

Now the compiler can be a little more helpful:

   Compiling foo v0.1.0 (.../foo)
tests/foo.rs:7:25: 7:48 error: no method named `uniq` found for type `collections::vec::Vec<u8>` in the current scope
tests/foo.rs:7     vec![1u8,2,3,4,5,6].uniq( vec![1,2,5,7,9] ),
                                       ^~~~~~~~~~~~~~~~~~~~~~~
<std macros>:1:1: 9:39 note: in expansion of assert_eq!
tests/foo.rs:6:3: 9:5 note: expansion site
tests/foo.rs:7:25: 7:48 note: the method `uniq` exists but the following trait bounds were not satisfied: `u8 : core::iter::Iterator`
<std macros>:5:8: 5:18 error: the type of this value must be known in this context

So, the problem is the Iterator trait bound. In fact if I remove it, the integration tests compile fine:

==> src/lib.rs <==
pub trait Uniq<T>{
  fn uniq(&self, other: Vec<T>) -> Self;
}

impl<T: Clone + PartialEq> Uniq<T> for Vec<T> {
  fn uniq(&self, _other: Vec<T>) -> Vec<T> {
    unimplemented!()
  }
}

Iterator is for types which are, themselves, iterators, so your original bound is a bit strange (it applies only to vectors which contain iterators, which are a bit uncommon). I think this new bound will work, although (it is not entirely clear what your uniq is intended to do) you may find later that you also need Hash.


#4

Thank you! This solves it. Removing the Iterator type definitely was important for this to work. I believe I came across this around the time you posted the answer.

I ended up with

pub trait Uniq{
  fn uniq(&self, other: Self) -> Self;
}

impl<T: Clone + PartialEq> Uniq for Vec<T> {
  fn uniq(&self, other: Vec<T>) -> Vec<T> {
    // code
  }
}

and in the integration test I needed

use mylib::Uniq;

And it works! I may have been missing the proper use of use as well in the test.

I’m happy to find I knew more than I thought I did and I wasn’t that far of from the correct implementation. :smiley:


#5

I’ve released it in a crate called array_tool . I plan to have common Array like methods available for people in this package.