# [Solved] Function taking slice of objects as well as slice of references to objects

#1

Hello everybody,

after applying a few combinators to a slice of objects `&[T]` I end up with a slice of references `&[&T]` which I like to process in another function. So the function parameter must be of type `&[&T]`. In order to reuse this function, I have to convert slice of objects to slices of references which is cumbersome and feels wrong. I’m wondering, if I’m missing something here which would allow me to resolve this in a more elegant way.

Here is a simplified example – cf. Playground.

``````struct Age {
pub age: u32,
}

fn process_ages(ages: &[Option<Age>]) -> u32 {
let somes: Vec<&Age> = ages.iter()
.filter(|x| x.is_some())
.map(|x| x.as_ref().unwrap())
.collect();

sum_ages(&somes)
}

fn sum_ages(ages: &[&Age]) -> u32 {
ages.iter().fold(0, |acc, e| acc + e.age)
}

fn main() {
let ages: Vec<Option<Age>> = vec![Some(Age { age: 1 }), None, Some(Age { age: 2 })];

assert_eq!(process_ages(&ages), 3);
}
``````

In this example, the total sum of all ages from a list of `Option<Age>`s should be computed. The function of interest is `sum_ages` that takes a slice of type `&[&Age]` instead a of slice of `&[Age]` which is more general and more applicable.

Do you have any idea how to ease the pain and make `sum_ages` reusable without requiring a transformation of `&[&Age]` to `&[&Age]` all the time?

#2

You can avoid getting references by using `ages.into_iter()` or `ages.iter().cloned()` (they iterate over `T` instead of `&T`).

As for `fn sum_ages`, you could make it take an iterator: https://play.rust-lang.org/?gist=65c07a66102749a7145d9f8cd45b546e&version=stable

#3

If you want to skip the cloning, you could use the `AsRef` trait (playground).

``````impl AsRef<Age> for Age {
fn as_ref(&self) -> &Age {
self
}
}

fn sum_ages_2<A: AsRef<Age>>(ages: &[A]) -> u32 {
ages.iter().fold(0, |acc, e| acc + e.as_ref().age)
}

fn process_ages(ages: &[Option<Age>]) -> u32 {
let somes: Vec<&Age> = ages.iter()
.filter(|x| x.is_some())
.map(|x| x.as_ref().unwrap())
.collect();

sum_ages_2(&somes)
}

fn main() {
let ages: Vec<Option<Age>> = vec![Some(Age { age: 1 }), None, Some(Age { age: 2 })];

assert_eq!(process_ages(&ages), 3);

let moar_ages = vec![Age { age: 1 }, Age { age: 2 }];
assert_eq!(sum_ages_2(&moar_ages), 3);
}

``````

This works because you are effectively “abstracting” over whether you have something or a reference to it. In this case, as long as you can get a reference to the thing then that’s all we care about.

#4

I was already pondering about using `AsRef` but it strikes me as odd that I need to set a property of the object in order to ease on how I pass it to functions. I will follow this path nevertheless.

#5

I have a question about your vector. You are storing Option in the vector. Is this something that’s okay to do? It seems like you’d have to go through extra work to make sure that option contains something later on, rather than just storing Age in the vector.

I only ask because I’m still learning Rust.

#6

Hello @jeramyRR,

yes, that’s perfectly fine to do.

`Option` and its sibling `Result` are types that encapsulate the result of a computation that might have not produced a valid result or even failed doing so, respectively. So if you apply such a computation to a set of input objects you end up with a list of `Option`s or `Result`s that are used in a following step of your algorithm.

In my actual case, I get a vector of `Result`s from the first step of my algorithm. The second step of my algorithm is only interested in successful results of step 1. So I need to filter / partition the results before I hand them over to the second step. But it has been easier to make up a minimized example using `Option`.

I hope this helps,
Lukas

#7

what is the most idiomatic way here to implements `AsRef` and use it or to use `Borrow` with has a blanko impl for `Borrow<T> for T`?

#8

I believe `AsRef` and `Borrow` meant for two slightly different things. `AsRef` abstracts over whether you have a reference or own the resource, whereas `Borrow` abstracts over whether you have a mutable or immutable reference.

I believe The Book has a chapter explaining more.

#9

from the book:

The `Borrow` trait is used when you’re writing a data structure, and you want to use either an owned or borrowed type as synonymous for some purpose.

sounds to me like that `Borrow` is the preferred way here.