Closed egolep closed 3 weeks ago
I am by no means a rust expert, but here is my best attempt at an explanation.
If you look at the implementation of the .collect()
in iterator ref, you'll notice a <B>
in the function definition, which means it is a generic. You can learn more about generics here.
Basically, the collect()
method is implemented for Vec<String>
and String
and for many other types. So, when yo do the capitalize_words_vector
the compiler infers that the variant of the collect method to be used must be the one that returns Vec<String>
and in the function capitalize_words_string
would use the variant or version of the collect method that returns the type String
Hint: you'll notice that the reduce
method is also generic. [ref](fn reduce
Hopefully that answers your question, feel free to ask more!
Thanks @frroossst for your reply. It makes it definitely more clear (I also read the .collect()
documentation in the meanwhile) and I now generally understand how it work.
I still have a doubt, though: how can I understand how the .collect()
method will work before using it? Is there a general criterion I can refer to or do I have to go and look for the specific implementation of the method for the type I'm going to use?
Also, here is a simple example to further illustrate what generics do
fn larger<T: PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
}
fn main() {
let x = 5;
let y = 10;
let result = larger::<i32>(x, y);
// let result = larger::<i32>(x, y);
println!("The larger value is: {}", result);
let s1 = "apple";
let s2 = "banana";
let result_str = larger::<&str>(s1, s2);
// let result_str = larger::<&str>(s1, s2);
println!("The larger string is: {}", result_str);
}
the larger function is generic, meaning it can work for multiple data types, in this example it works for both &str
and i32
, now we can help the compiler explicitly using the <type>
syntax or we can leave that out and let the compiler automatically figure out what version or variant of the generic function to use. If you were using larger on your own structs or enum type for example, you would have to implement the PartialOrd trait.
But to answer your question. I think a lot of knowing which method to use comes from writing code. Suppose you have never had to use the *
operator to multiply two numbers over. So, you wouldn't need to know that it even exists. But one day, you need to multiply two numbers so you look at the documentation and find out that the *
operator exists. Now, the next time you need to solve a similar problem, you'll be like hmm... I've run into this before, what operator was it? and you look again, and go AH! it was the *
operator. And by the third and fourth time, you'll simply remember.
The more you use something the more likely you are to remember how to use it and what to use to solve your problem.
apologies for the long answer, hope it helped.
That's super useful, thanks you. Especially the possibility to suggest the specific type to use for the generics.
However, my doubt is slightly different: let's say I decided to use .collect()
for String
. Before using it, how can I know that the result will be the concatenation of all the strings instead of, for example, a different merge where I take the first letter from all strings, then the second and so on?
I guess that the simpler answer is always the right one. I'm afraid there may be corner cases where it is not easy to understand what the simpler answer is, but this is probably what you mean with "I think a lot of knowing which method to use comes from writing code".
Thank you again for your replies, they were very useful and insightful.
I was doing the
iterators2
exercise and I had completedcapitalize_words_vector
as:which is the right solution. Then, I write
capitalize_words_string
as:which also works fine. Out of curiosity, I looked at the solution and find out that
capitalize_word_string
is written as:which is exactly the same as
capitalize_word_vector
but with a different return type. How can this be correct? Does the compiler looks at the return type and automatically add a.reduce
?