colin-kiegel / rust-derive-builder

derive builder implementation for rust structs
https://colin-kiegel.github.io/rust-derive-builder/
Apache License 2.0
1.32k stars 88 forks source link

Using default generic parameter types for skippable fields #198

Closed srithon closed 3 years ago

srithon commented 3 years ago

In a project I'm working on, I have an immutable buildable struct that contains an optional generic field. When this field is not set, the compiler throws an error because it cannot infer its type.

However, since the struct is immutable, this field would stay None forever, meaning that its corresponding type would not be relevant. I attempted to fix this by giving it a Default Generic Type Parameter with a throwaway type, but it did not work as I expected.

This is a minimal example of the issue.

I set the placeholder type to Vec<String> because in my project the type of B has bounds which prevent it from being ().

use derive_builder::Builder;

#[derive(Builder)]
struct GenericStruct<A, B = Vec<String>> {
    required_field: A,

    #[builder(setter(strip_option), default)]
    optional_field: Option<B>
}

fn main() {
    let a = GenericStructBuilder::default()
        .optional_field(30)
        .required_field("hello")
        .build();

    // **Error**
    let b = GenericStructBuilder::default()
        .required_field("hello")
        .build();
}
error[E0282]: type annotations needed for `std::result::Result<GenericStruct<&str, B>, String>`
  --> src/main.rs:18:13
   |
18 |     let b = GenericStructBuilder::default()
   |         -   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the struct `GenericStructBuilder`
   |         |
   |         consider giving `b` the explicit type `std::result::Result<GenericStruct<&str, B>, String>`, where the type parameter `B` is specified

Potential User Workarounds

  1. Remove strip_option and default, and make users explicitly pass in Option::<()>::None to the setter
  2. Something with Box?

Potential Crate Solutions

  1. Internally use workaround #1 before build() to set the type

Other Notes

Resources

TedDriggs commented 3 years ago

I'm not sure there's anything this crate can do, I'm afraid.