let f: Test = Test { foo: None }
let f = Test { foo: None::<String> }
#[derive(Debug, Default)]
// ^^^^^^^
struct Test<T = String>{
foo:Option<T>
}
// ...
let f = <Test>::default();
Default values for generic parameters have only one effect: they allow you to omit the generic parameters when writing down the type. You don't write the Test type anywhere, so the default is not used anywhere.
As a rule of thumb, if you have some code that would still compile without "you need to specify this generic parameter" errors when you remove the default, then adding a default has no effect on that code.
I did believe that T:: and <T>:: were equivalent, but it's not the case.
What's the difference between T:: and <T>::? Can somebody explain to me why this hack actually works?
Types in part of a (path) expression, like T::, use inference for all elided type parameters -- including defaulted ones -- and do not fallback to the defaulted type when running into ambiguity. That's pretty much what this RFC was about. So these are equivalent and cannot currently fallback to the defaulted type (and thus fail to compile):
let _ = Foo::Baz;
let _ = Foo::<_>::Baz;
Where as in type ascription location, you can't elide non-defaulted parameters, but if you elide defaulted parameters they take on the default value. (Then the inferred type parameter in the expression can be resolved from the ascription.) So these are all the same and compile:
let _: Foo = Foo::Baz;
let _: Foo<String> = Foo::Baz;
let _: Foo = Foo::<_>::Baz;
let _: Foo<String> = Foo::<_>::Baz;
And then we have <T>:: in an expression. The T in <T> is always a type -- on its own inside the <>, T is not part of an expression. Similar to type ascription, you can't elide non-defaulted parameters, but if you elide default parameters they take on the default value. So these are the same:
let _ = <Foo>::Baz;
let _ = <Foo<String>>::Baz;
<T> was introduced in RFC 0132, which also says that Foo::<_>::... is now equivalent to <Foo<_>>::.... And sure enough, these don't compile either, as the inference still does not fallback to defaults.
let _ = <Foo<_>>::Baz;
let _: Foo<_> = Foo::Baz;
Summary
In an expression position (where you need turbofish)
You can elide parameters whether they are defaulted or not
Elided parameters, with or without a default, will become fresh inference variables (_)
Which do not fallback to parameter defaults
In a type position (where you don't need turbofish)
You cannot elide non-default parameters
Elided default parameters will use the default, not inference