the other day and I have no idea what this is doing, but I'm pretty sure it compiled.
I attemped to google "rust call method on type parameter" and "rust call method on trait bound" but got nothing back, and crapgpt was no help either. I've been doing rust for quite a bit and have never seen this before, so I feel it must be some kind of obscure syntax thing.
Please enlighten me as to what on earth is going on here.
You might have seen something like this, demonstrating use of fully qualified syntax:
struct SomeStruct {}
trait SomeTrait {
fn some_method(&self);
}
impl SomeTrait for SomeStruct {
fn some_method(&self) {}
}
fn something<T: SomeTrait>(thingy: T) {
// Call method the usual way on this instance of thingy
thingy.some_method();
// Call method via it's fully qualified name passing this thingy as the self parameter
T::some_method(&thingy);
}
T::some_method() can also be what Rust calls an associated function and many other languages call static methods or class methods – ie. just a normal function with a fancy name. For example, Vec::new() (though that one is of course not a trait function but an inherent one).
struct SomeStruct {}
trait SomeTrait {
// Associated function (sstatic method). No self parameter
fn some_func();
}
impl SomeTrait for SomeStruct {
fn some_func() {}
}
fn something<T: SomeTrait>(thingy: T) {
// Cannot do this because some_func has no self parameter
//thingy.some_func();
// Call associated function via it's fully qualified name
T::some_func();
}
I found the code snippet that was doing my head in, and it's this from this page on the serde book:
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = Deserializer::from_str(s);
let t = T::deserialize(&mut deserializer)?;
if deserializer.input.is_empty() {
Ok(t)
} else {
Err(Error::TrailingCharacters)
}
}
I was a bit confused about it being fully qualified synatax, it made sense at first and I was just "Ohh that's just another form of fully qualified" but I just read up on fully qualified and it seems you'd need to do <T as SomeTrait>::some_func() for it to be that, but reading the later reply and the docs for Deserialize::deserialize where there's no self parameter it seems as if it could be calling a static function as where ZiCog said it's a "associated function". So I guess that's something.
trait Trait<One, Two = String>: Sized { ... }
// These act the same
let _: (i32, (), _) = Trait::foo(0);
let _: (i32, (), _) = Trait::<_, _>::foo(0);
let _: (i32, (), _) = <_ as Trait<_, _>>::foo(0);
// These act the same
let _: (i32, (), _) = Trait::<_>::foo(0);
let _: (i32, (), _) = <_ as Trait<_>>::foo(0);
struct HashSet<Key, S = RandomState> { .. }
// These act the same (and would search for inherent functions)
let mut hs = HashSet::default();
let mut hs = HashSet::<>::default();
let mut hs = HashSet::<_, _>::default();
let mut hs = <HashSet::<_, _>>::default();
// Mostly the same but only looks at the `Default` trait
let mut hs = <HashSet::<_, _> as Default>::default();
// These act the same (and would search for inherent functions)
let mut hs = HashSet::<_>::default();
let mut hs = <HashSet<_>>::default();
// Mostly the same but only looks at the `Default` trait
let mut hs = <HashSet<_> as Default>::default();
In the example in question T::some_func(); is not a call to a function of the type T, but of the (only) trait SomeTrait which T implements. That's how generics work.
The compiler cannot make any assumptions about T's methods if it is not bound by trait bounds.
And it can only resolve this to a specific trait's method if it isn't ambiguous:
Otherwise you'd need to call SomeTrait::some_func() explicitly, or, more explicitly <T as SomeTrait>::some_func().
So T::some_method() can never be a call to an associated function if T is a generic type parameter, only if T is a concrete type, like struct T { ... }.
Also associated functions and class methods (or static methods) are unrelated principles.
You can have associated functions, which take self or don't and you can have trait methods, which take self or don't.
I think I'm confused by naming/terminology. If T::some_method() in the OP's example is not a call to an associated function then what is the thing it is calling actually called?
Associated functions whose first parameter is named self are called methods and may be invoked using the method call operator, for example, x.foo() , as well as the usual function call notation.
Afaik, for the lack of a better term in Rust we call associated functions without a self parameter simply associated functions, to differentiate them from methods. Thus being what are called static methods in other PLs.