let v: Vec<u8> = b"3q2+7w==".iter().cloned().collect();
and let v: HashSet<u8> = b"3q2+7w==".iter().cloned().collect();
are both valid, even though both statements have the same expression on the right hand side. In a language like Java you could assign a value to different types based on a sub-type / super-type relationship (Object foo = Arrays.asList(...)), but that's not the case here, nor is it the case that Vec<u8> and HashSet<u8> have the same layout in memory. Instead, according to the thread, the result from collect can be interpreted as any type that implements the FromIterator trait.I don't know what the name for this sort of behavior is, and I haven't seen it in other languages. Perhaps it's just a property of Rust's trait system? Regardless, it feels intuitive to me - like the compiler is taking type information and using it to make implicit casts throughout the program.
Not a huge impediment - just something I found confusing that isn't related to the borrow checker.
[0] https://users.rust-lang.org/t/why-cant-the-compiler-the-type...
What's throwing him off is static method dispatch based on type inference on the return value.
Haskell, for example, does this too:
class Foo a where foo :: a
instance Foo Integer where foo = 3
instance Foo Char where foo = '*'
foo1 :: Integer
foo1 = foo
foo2 :: Char
foo2 = foo
main = do
print foo1 -- prints: 3
print foo2 -- prints: '*'It's not a cast. Rather, it's an inferred/omitted type parameter. In this case, the collect() method is actually collect::<ContainerType>(). So it's not that collect returns something to be cast, but rather that there is a different collect() implementation for each target type. When the compiler is able to infer the target type unambiguously -- for example here, because you assign it to a typed variable -- then you don't have to specify it.