Parâmetros opcionais são argumentos que não precisam ser fornecidos ao chamar uma função. Eles possuem valores padrão que são utilizados quando nenhum valor é passado, trazendo flexibilidade ao código.
Diferente de linguagens como Python e PHP, o Go não oferece suporte nativo a parâmetros opcionais.
Para se obter esse comportamento no Go, apresento três soluções.
1. Struct de parâmetros
A primeira abordagem é utilizar structs para encapsular os parâmetros opcionais, enquanto os obrigatórios permanecem na assinatura da função:
type Config struct {
    Port int
}
func NewServer(addr string, cfg Config) {
}
Essa técnica facilita a adição de novos parâmetros sem quebrar a compatibilidade com chamadas existentes.
Entretanto, é importante lembrar que quando criamos uma struct sem passar valores para seus campos, eles são inicializados com seus zero values:
0para inteiros0.0para floats""para stringsnilpara slices, maps, channels, ponteiros, interfaces e funções
Se for necessário distinguir entre um valor 0 em um inteiro passado pelo cliente e o zero value do tipo, pode-se usar ponteiros, pois seu zero value será nil.
type Config struct {
    Port *int
}
Apesar de funcional, essa abordagem exige a criação explícita de variáveis para referência:
port := 0
config := httplib.Config{
    Port: &port,
}
Outro ponto de atenção ao ponteiro é que se ele não for bem tratado existe o risco do programa gerar um panic por nil pointer exception. 
Outro ponto negativo de utilizar uma struct como parâmetro opcional é que, se esse parâmetro não for utilizado, ainda será necessário passar uma struct vazia na chamada da função:
httplib.NewServer("localhost", httplib.Config{})
11. Builder
O padrão de projeto Builder delega a criação e validação da struct Config para uma struct intermediária ConfigBuilder, que expõe métodos para configurar os campos:
type ConfigBuilder struct {
    port *int
}
func (b *ConfigBuilder) Port(port int) *ConfigBuilder {
    b.port = &port
    return b
}
func (b *ConfigBuilder) Build() (Config, error) {
    // lógica de validação e preenchimento
}
Um exemplo de uso pelo cliente seria:
builder := httplib.ConfigBuilder{}
builder.Port(8080)
cfg, err := builder.Build()
if err != nil {
    return err
}
server, err := httplib.NewServer("localhost", cfg)
if err != nil {
    return err
}
Essa abordagem também resolve o problema de compatibilidade e facilita validações complexas, mas adiciona uma camada extra de abstração.
111. Function Optional Pattern
O Function Optional Pattern é um padrão onde uma função principal recebe uma lista de funções opcionais como argumento.
Essas funções extras são usadas para modificar ou estender o comportamento da função principal, mas sem serem obrigatórias.
Se forem passadas, elas são executadas em determinado ponto do código; caso contrário, a função segue com o comportamento padrão.
No Go, esse padrão pode ser aplicado com o uso de parâmetros variádicos, que permitem que uma função receba zero ou mais argumentos de um mesmo tipo.
Um parâmetro variádico é declarado com ... antes do tipo e os argumentos são tratados como um slice dentro da função.
func sum(numbers ...int) int {
    sum := 0
    for _, n := range numbers {
        sum += n
    }
    return sum
}
Passo a passo para usar o padrão
1. Criar uma struct interna de configuração
type options struct {
    port *int
}
2. Definir um tipo de função que recebe um ponteiro para a struct criada
type Option func(*options) error
3. Criar funções públicas que retornam o tipo definido
Essas funções alterarão os campos da struct options.
Esse padrão permite criar quantas funções WithX forem necessárias (WithTimeout, WithTLS, etc.), mantendo a função principal limpa.
func WithPort(port int) Option {
    return func(o *options) error {
        if port < 0 {
            return errors.New("port should be positive")
        }
        o.port = &port
        return nil
    }
}
4. Definir a função principal com parâmetros variádicos
func NewServer(addr string, opts ...Option) (*http.Server, error)
5. Processar a lista de funções opcionais dentro da função
func NewServer(addr string, opts ...Option) (*http.Server, error) {
    var o options
    for _, opt := range opts {
        if err := opt(&o); err != nil {
            return nil, err
        }
    }
    // ...
}
Com essa solução podemos chamar a função NewServer somente com o parâmetro obrigatório addr:
server, err := httplib.NewServer("localhost")
Ou com vários parâmetros opcionais:
server, err := httplib.NewServer("localhost",
httplib.WithPort(8080),
httplib.WithTimeout(time.Second))
Embora o Go não ofereça suporte nativo a parâmetros opcionais, existem padrões eficazes para contornar essa limitação, como o uso de structs, builders e funções variádicas. A escolha da abordagem ideal depende da complexidade da configuração, da necessidade de validação e da escalabilidade do código.
Referência: HARSANYI, Teiva. 100 Go mistakes and how to avoid them. Shelter Island: Manning, 2022.