4 ms·
Something that I've found confusing in Rust: the fact that the return type of a function call seems to depend on how the returned value is used. This thread [0]
by caditinpiscinam 6y ago
Something that I've found confusing in Rust: the fact that the return type of a function call seems to depend on how the returned value is used. This thread [0] has the following example, where the statements:
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-of-an-iterator-collect-call/13707 https://users.rust-lang.org/t/why-cant-the-compiler-the-type...
- lights0123 6y agoIt's called type inference: https://doc.rust-lang.org/rust-by-example/types/inference.html https://doc.rust-lang.org/rust-by-example/types/inference.ht...
- Phlogistique 6y agoI don't think that's what the parent comment is pointing at. 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: '*'
- oconnor663 6y ago> like the compiler is taking type information and using it to make implicit casts throughout the program. 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.
- caditinpiscinam 6y agoAh, I see - the "inferred/omitted type parameter" is the part I was missing. Really no different than Arrays.asList in my previous comment. Thanks!