The important bit here is:
Basically, what happens if somebody wrote test::<i32>::new()? The generic parameter expresses the fact that, as an implementor, you can work with any type the caller may give you. In order to support such a claim, your code needs to be compatible with all possible choices of T. Yes, that choice of T may be (), but it may also be any other type.
If, within your function's body, you are only able to construct instances of externalType<()> (through f()), then that means that you are not able to produce externalType<T> for any caller-chosen type T, such as externalType<i32>.
That's why Rust complained. You either need to be able to construct Option<testType<T>> for any arbitrary type T, such as with None, as @2e71828 suggested, or you need to express that you can only handle T = (), by removing the caller-chosen genericity, and replacing it with a fixed usage of (), as I've suggested.
You could even go the extra mile:
enum TestType /* no generics */ {
Item(ExternalType<()>), // Start using `()` already
}
struct Test /* no generics */ {
example: Option<TestType /* no generics */ >,
}
impl Test {
fn new() -> Self {
let a = TestType::Item(f());
Self {
example: Some(a),
}
}
}
(In the event the return type of f() cannot be named, then this solution won't work on its own, and will require a bit of extra effort. That being said, you explicitly talk about the unit type, so I don't think this is your case. If it were, then feel free to ask about it, there are other threads in this forum where have talked in length about constructing types with impl Trait / unnameable types inside them.)