Base de Conhecimento

Como usar funções variáveis ​​em Go  Imprimir este Artigo

Introdução

Uma função variável é uma função que aceita zero, um ou mais valores como um único argumento. Embora as funções variadas não sejam o caso comum, elas podem ser usadas para tornar seu código mais limpo e legível.

Funções variáveis ​​são mais comuns do que parecem. O mais comum é a Printlnfunção do fmtpacote.

func Println(a ...interface{}) (n int, err error)

Uma função com um parâmetro que é precedido por um conjunto de elipses ( ...) é considerada uma função variável. As reticências significam que o parâmetro fornecido pode ser zero, um ou mais valores. Para o fmt.Printlnpacote, está declarando que o parâmetro aé variável.

Vamos criar um programa que use a fmt.Printlnfunção e passar zero, um ou mais valores:

print.go
package main

import "fmt"

func main() {
    fmt.Println()
    fmt.Println("one")
    fmt.Println("one", "two")
    fmt.Println("one", "two", "three")
}

A primeira vez que fmt.Printlnligamos, não passamos nenhum argumento. Na segunda vez que chamamos fmt.Println, passamos apenas um único argumento, com o valor de oneEntão nós passamos onetwo, e, finalmente onetwothree.

Vamos executar o programa com o seguinte comando:

  • go run print.go

Veremos a seguinte saída:

Output

one
one two
one two three

A primeira linha da saída está em branco. Isso ocorre porque não passamos nenhum argumento da primeira vez que fmt.Printlnfoi chamado. A segunda vez que o valor de onefoi impresso. Em seguida, onetwo, e, finalmente onetwothree.

Agora que vimos como chamar uma função variadica, vejamos como podemos definir nossa própria função variadica.

Definindo uma função variável

Podemos definir uma função variável usando reticências ( ...) na frente do argumento. Vamos criar um programa que cumprimente as pessoas quando seus nomes forem enviados para a função:

hello.go
package main

import "fmt"

func main() {
    sayHello()
    sayHello("Sammy")
    sayHello("Sammy", "Jessica", "Drew", "Jamie")
}

func sayHello(names ...string) {
    for _, n := range names {
        fmt.Printf("Hello %s\n", n)
    }
}

Criamos uma sayHellofunção que usa apenas um único parâmetro chamado namesO parâmetro é aridade variável, como vamos colocar reticências ( ...) antes de o tipo de dados: ...stringIsso indica ao Go que a função pode aceitar zero, um ou muitos argumentos.

sayHellofunção recebe o namesparâmetro como a sliceComo o tipo de dados é a string, o namesparâmetro pode ser tratado como uma fatia de strings ( []string) dentro do corpo da função. Podemos criar um loop com o rangeoperador e iterar através da fatia de strings.

Se executarmos o programa, obteremos a seguinte saída:

Output
Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie

Observe que nada foi impresso pela primeira vez que ligamos sayHelloIsso ocorre porque o parâmetro variadic estava vazio slicede stringComo estamos percorrendo a fatia, não há nada para iterar e fmt.Printfnunca é chamado.

Vamos modificar o programa para detectar que nenhum valor foi enviado:

hello.go
package main

import "fmt"

func main() {
    sayHello()
    sayHello("Sammy")
    sayHello("Sammy", "Jessica", "Drew", "Jamie")
}

func sayHello(names ...string) {
    if len(names) == 0 {
        fmt.Println("nobody to greet")
        return
    }
    for _, n := range names {
        fmt.Printf("Hello %s\n", n)
    }
}

Agora, usando uma ifinstrução , se nenhum valor for passado, o comprimento de namesserá 0e nós imprimiremos nobody to greet:

Output
nobody to greet
Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie

O uso de um parâmetro variável pode tornar seu código mais legível. Vamos criar uma função que une palavras a um delimitador especificado. Primeiro, criaremos este programa sem uma função variável para mostrar como seria lido:

join.go
package main

import "fmt"

func main() {
    var line string

    line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"})
    fmt.Println(line)

    line = join(",", []string{"Sammy", "Jessica"})
    fmt.Println(line)

    line = join(",", []string{"Sammy"})
    fmt.Println(line)
}

func join(del string, values []string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}

Neste programa, estamos passando uma vírgula ( ,) como delimitador para a joinfunção. Então, estamos passando uma fatia de valores para ingressar. Aqui está a saída:

Output
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy

Como a função usa uma fatia de string como valuesparâmetro, tivemos que agrupar todas as nossas palavras em uma fatia quando chamamos a joinfunção. Isso pode dificultar a leitura do código.

Agora, vamos escrever a mesma função, mas usaremos uma função variável:

join.go
package main

import "fmt"

func main() {
    var line string

    line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
    fmt.Println(line)

    line = join(",", "Sammy", "Jessica")
    fmt.Println(line)

    line = join(",", "Sammy")
    fmt.Println(line)
}

func join(del string, values ...string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}

Se rodarmos o programa, podemos ver que obtemos a mesma saída que o programa anterior:

Output
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy

Enquanto ambas as versões da joinfunção fazem exatamente a mesma coisa programaticamente, a versão variável da função é muito mais fácil de ler quando está sendo chamada.

Ordem de argumento variável

Você pode ter apenas um parâmetro variável em uma função e deve ser o último parâmetro definido na função. Definir parâmetros em uma função variável em qualquer ordem que não seja o último parâmetro resultará em um erro de compilação:

join.go
package main

import "fmt"

func main() {
    var line string

    line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
    fmt.Println(line)

    line = join(",", "Sammy", "Jessica")
    fmt.Println(line)

    line = join(",", "Sammy")
    fmt.Println(line)
}

func join(values ...string, del string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}

Desta vez, colocamos o valuesparâmetro em primeiro lugar na joinfunção. Isso causará o seguinte erro de compilação:

Output
./join_error.go:18:11: syntax error: cannot use ... with non-final parameter values

Ao definir qualquer função variável, apenas o último parâmetro pode ser variável.

Argumentos explosivos

Até agora, vimos que podemos passar zero, um ou mais valores para uma função variável. No entanto, haverá ocasiões em que temos uma fatia dos valores e queremos enviá-los para uma função variável.

Vejamos nossa joinfunção da última seção para ver o que acontece:

join.go
package main

import "fmt"

func main() {
    var line string

    names := []string{"Sammy", "Jessica", "Drew", "Jamie"}

    line = join(",", names)
    fmt.Println(line)
}

func join(del string, values ...string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}

Se executarmos este programa, receberemos um erro de compilação:

Output
./join-error.go:10:14: cannot use names (type []string) as type string in argument to join

Embora a função variadic converta o parâmetro de values ...stringem uma fatia de strings []string, não podemos passar uma fatia de strings como argumento. Isso ocorre porque o compilador espera argumentos discretos de cadeias.

Para contornar isso, podemos explodir uma fatia sufixando-a com um conjunto de elipses ( ...) e transformando-a em argumentos discretos que serão passados ​​para uma função variada:

join.go
package main

import "fmt"

func main() {
    var line string

    names := []string{"Sammy", "Jessica", "Drew", "Jamie"}

    line = join(",", names...)
    fmt.Println(line)
}

func join(del string, values ...string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}

Dessa vez, quando chamamos a joinfunção, explodimos a namesfatia anexando elipses ( ...).

Isso permite que o programa seja executado agora como esperado:

Output
Sammy,Jessica,Drew,Jamie

É importante observar que ainda podemos passar um zero, um ou mais argumentos, além de uma fatia que explodimos. Aqui está o código que passa todas as variações que vimos até agora:

join.go
package main

import "fmt"

func main() {
    var line string

    line = join(",", []string{"Sammy", "Jessica", "Drew", "Jamie"}...)
    fmt.Println(line)

    line = join(",", "Sammy", "Jessica", "Drew", "Jamie")
    fmt.Println(line)

    line = join(",", "Sammy", "Jessica")
    fmt.Println(line)

    line = join(",", "Sammy")
    fmt.Println(line)

}

func join(del string, values ...string) string {
    var line string
    for i, v := range values {
        line = line + v
        if i != len(values)-1 {
            line = line + del
        }
    }
    return line
}
Output
Sammy,Jessica,Drew,Jamie
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy

Agora sabemos como passar zero, um ou muitos argumentos, bem como uma fatia que explodimos, para uma função variada.

Conclusão

Neste tutorial, vimos como funções variadas podem tornar seu código mais limpo. Embora você nem sempre precise usá-los, pode ser útil:

  • Se você achar que está criando uma fatia temporária apenas para passar para uma função.
  • Quando o número de parâmetros de entrada é desconhecido ou varia quando chamado.
  • Para tornar seu código mais legível.

Esta resposta lhe foi útil?

Veja também

Como usar variáveis ​​no Python 3
Introdução Variáveis são um importante conceito de programação a ser dominado. Eles são...
Como escrever e executar seu primeiro programa no Node.js
Introdução O Node.js é um ambiente de tempo de execução de código aberto popular que pode...
Como instalar o Node.js no Debian 10
Introdução O Node.js é uma plataforma JavaScript para programação de uso geral que permite aos...
Introdução ao Kubernetes: dicas do kubectl
Introdução O Kubectl é uma ferramenta de linha de comando projetada para gerenciar objetos e...
Como instalar o Python 3 e configurar um ambiente de programação local no Windows 10
Introdução Python é uma linguagem de programação versátil que pode ser usada para muitos...