2

I am making a contact application for learning. I have a NewContact().

// Contact - defines the fields of an entire Contact
type Contact struct {
    Title     string
    FirstName string
    LastName  string
    HomePhone string
    WorkPhone string
    Mobile    string
    Address   *Address
    Email     string
}    
// NewContact - Creates a new contact
func NewContact(first string, last string) *Contact {
    c := &Contact{}
    c.FirstName = first
    c.LastName = last

    return c

}

This does work however....I can require a FirstName and LastName BUT how would I make ALL the other field arguments optional? Thank you in advance.

RedBloodMage
  • 77
  • 1
  • 1
  • 5
  • You could make it a variadic function, but it would be unclear to callers what each argument did since it would be exposed as a single variadic argument. Other than that, there is no way to have "optional" arguments in Go. – Adrian Dec 07 '17 at 17:28
  • 1
    Your constructor is just assigning fields from arguments. Why not just document what's required and not have a constructor at all? – JimB Dec 07 '17 at 17:30
  • See some techniques here: [Optional Parameters?](https://stackoverflow.com/questions/2032149/optional-parameters) – icza Dec 07 '17 at 17:34
  • I could have just what is required like the first and last name BUT it is about flexibility with a contact application. Maybe someone has just a firstname they wanted to drop in quick or a last name and phone number. Giving options and not forcing the enduser to drop in certain info. – RedBloodMage Dec 07 '17 at 17:43

1 Answers1

2

Only your use case, domain and the design can tell which approach is preferable. But you can:

1 - Use chaining methods:

func main() {
    c := new(Contact)
    c = c.SetEmail("...").SetFirstName("...").SetLastName("...")
}

type Contact struct {
    Title     string
    FirstName string
    LastName  string
    HomePhone string
    WorkPhone string
    Mobile    string
    Address   *Address
    Email     string
}

func (c *Contact) SetTitle(v string) *Contact     { c.Title = v; return c }
func (c *Contact) SetFirstName(v string) *Contact { c.FirstName = v; return c }
func (c *Contact) SetLastName(v string) *Contact  { c.LastName = v; return c }
func (c *Contact) SetHomePhone(v string) *Contact { c.HomePhone = v; return c }
func (c *Contact) SetWorkPhone(v string) *Contact { c.WorkPhone = v; return c }
func (c *Contact) SetMobile(v string) *Contact    { c.Mobile = v; return c }
func (c *Contact) SetAddress(v *Address) *Contact { c.Address = v; return c }
func (c *Contact) SetEmail(v string) *Contact     { c.Email = v; return c }

2 - Use functional options:

func main() {
    c := NewContact(FirstName("..."), LastName("..."))
    _ = c
}

type Contact struct {
    Title     string
    FirstName string
    LastName  string
    HomePhone string
    WorkPhone string
    Mobile    string
    Address   *Address
    Email     string
}

func NewContact(options ...ContactOption) *Contact {
    c := new(Contact)
    for _, opt := range options {
        opt(c)
    }
    return c
}

type ContactOption func(*Contact)

func Title(v string) ContactOption        { return func(c *Contact) { c.Title = v } }
func FirstName(v string) ContactOption    { return func(c *Contact) { c.FirstName = v } }
func LastName(v string) ContactOption     { return func(c *Contact) { c.LastName = v } }
func HomePhone(v string) ContactOption    { return func(c *Contact) { c.HomePhone = v } }
func WorkPhone(v string) ContactOption    { return func(c *Contact) { c.WorkPhone = v } }
func Mobile(v string) ContactOption       { return func(c *Contact) { c.Mobile = v } }
func SetAddress(v *Address) ContactOption { return func(c *Contact) { c.Address = v } }
func Email(v string) ContactOption        { return func(c *Contact) { c.Email = v } }
Kaveh Shahbazian
  • 13,088
  • 13
  • 80
  • 139
  • 1
    Thanks guys...Thanks Mr. Shahbazian for the suggestions there. I will use one of these I think or at least this gives options. Thanks for the link icza. – RedBloodMage Dec 07 '17 at 17:59
  • What is the opt() doing the contact is going inside it.. I do not see an opt() builtin – RedBloodMage Dec 07 '17 at 19:25
  • `opt` is an item inside `options` which is a slice of `ContactOption`. A `ContactOption` is a function that accepts a pointer to `Contanct` (`*Contact`), so every change will happen to the original instance. – Kaveh Shahbazian Dec 07 '17 at 20:58