Valor padrão no método Go

103

Existe uma maneira de especificar o valor padrão na função de Go? Estou tentando encontrar isso na documentação, mas não consigo encontrar nada que especifique que isso seja possível.

func SaySomething(i string = "Hello")(string){
...
}
denniss
fonte

Respostas:

128

NÃO, mas existem algumas outras opções para implementar o valor padrão. Existem algumas boas postagens em blogs sobre o assunto, mas aqui estão alguns exemplos específicos.


** Opção 1: ** O autor da chamada escolhe usar os valores padrão
// Both parameters are optional, use empty string for default value
func Concat1(a string, b int) string {
  if a == "" {
    a = "default-a"
  }
  if b == 0 {
    b = 5
  }

  return fmt.Sprintf("%s%d", a, b)
}

** Opção 2: ** Um único parâmetro opcional no final
// a is required, b is optional.
// Only the first value in b_optional will be used.
func Concat2(a string, b_optional ...int) string {
  b := 5
  if len(b_optional) > 0 {
    b = b_optional[0]
  }

  return fmt.Sprintf("%s%d", a, b)
}

** Opção 3: ** uma estrutura de configuração
// A declarative default value syntax
// Empty values will be replaced with defaults
type Parameters struct {
  A string `default:"default-a"` // this only works with strings
  B string // default is 5
}

func Concat3(prm Parameters) string {
  typ := reflect.TypeOf(prm)

  if prm.A == "" {
    f, _ := typ.FieldByName("A")
    prm.A = f.Tag.Get("default")
  }

  if prm.B == 0 {
    prm.B = 5
  }

  return fmt.Sprintf("%s%d", prm.A, prm.B)
}

** Opção 4: ** Análise completa de argumentos variados (estilo javascript)
func Concat4(args ...interface{}) string {
  a := "default-a"
  b := 5

  for _, arg := range args {
    switch t := arg.(type) {
      case string:
        a = t
      case int:
        b = t
      default:
        panic("Unknown argument")
    }
  }

  return fmt.Sprintf("%s%d", a, b)
}
diretor
fonte
99
Que dor. Eu gostaria que fosse: func Concat1(a string = 'foo', b int = 10) string {como na maioria das outras linguagens modernas ... Isso reduziria qualquer um dos exemplos dados praticamente a uma linha de código.
Rotareti
Temos a opção de escrever duas funções diferentes e deixar que o chamador seja explícito sobre o que ele espera.
ProgramCpp de
@ProgramCpp não, golang não permite sobrecarga de função A linguagem Go tem sobrecarga de função / método?
Vusal
11

Não, não há como especificar padrões. Acredito que isso seja feito de propósito para melhorar a legibilidade, ao custo de um pouco mais de tempo (e, espero, de reflexão) no final do escritor.

Acho que a abordagem adequada para ter um "padrão" é ter uma nova função que forneça esse padrão para a função mais genérica. Tendo isso, seu código se torna mais claro em sua intenção. Por exemplo:

func SaySomething(say string) {
    // All the complicated bits involved in saying something
}

func SayHello() {
    SaySomething("Hello")
}

Com muito pouco esforço, criei uma função que faz uma coisa comum e reutilizei a função genérica. Você pode ver isso em muitas bibliotecas, fmt.Printlnpor exemplo, apenas adiciona uma nova linha ao que fmt.Printfaria de outra forma. Ao ler o código de alguém, no entanto, fica claro o que eles pretendem fazer pela função que chamam. Com os valores padrão, não saberei o que deve estar acontecendo sem também acessar a função para fazer referência a qual é o valor padrão.

Dave
fonte
Eu gosto e concordo com essa resposta, mas caramba, eu ainda gostaria que eles tivessem pelo menos uma maneira obtusa, mas idiomática de fazer isso.
Sam Gomena
15
O argumento "basta adicionar outra função" pode resultar em uma explosão de métodos necessários para lidar com múltiplas permutações, requer o fardo de decidir sobre nomes significativos, detectáveis ​​e lembráveis ​​para esses métodos e adiciona peso para aprender os pacotes que usam mais métodos vs. . Menos. #jmtcw
MikeSchinkel