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 Println
função do fmt
pacote.
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.Println
pacote, está declarando que o parâmetro a
é variável.
Vamos criar um programa que use a fmt.Println
função e passar zero, um ou mais valores:
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.Println
ligamos, não passamos nenhum argumento. Na segunda vez que chamamos fmt.Println
, passamos apenas um único argumento, com o valor de one
. Então nós passamos one
e two
, e, finalmente one
, two
e three
.
Vamos executar o programa com o seguinte comando:
- go run print.go
Veremos a seguinte saída:
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.Println
foi chamado. A segunda vez que o valor de one
foi impresso. Em seguida, one
e two
, e, finalmente one
, two
e three
.
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:
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 sayHello
função que usa apenas um único parâmetro chamado names
. O parâmetro é aridade variável, como vamos colocar reticências ( ...
) antes de o tipo de dados: ...string
. Isso indica ao Go que a função pode aceitar zero, um ou muitos argumentos.
A sayHello
função recebe o names
parâmetro como a slice
. Como o tipo de dados é a string
, o names
parâmetro pode ser tratado como uma fatia de strings ( []string
) dentro do corpo da função. Podemos criar um loop com o range
operador e iterar através da fatia de strings.
Se executarmos o programa, obteremos a seguinte saída:
Hello Sammy
Hello Sammy
Hello Jessica
Hello Drew
Hello Jamie
Observe que nada foi impresso pela primeira vez que ligamos sayHello
. Isso ocorre porque o parâmetro variadic estava vazio slice
de string
. Como estamos percorrendo a fatia, não há nada para iterar e fmt.Printf
nunca é chamado.
Vamos modificar o programa para detectar que nenhum valor foi enviado:
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 if
instrução , se nenhum valor for passado, o comprimento de names
será 0
e nós imprimiremos nobody to greet
:
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:
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 join
função. Então, estamos passando uma fatia de valores para ingressar. Aqui está a saída:
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
Como a função usa uma fatia de string como values
parâmetro, tivemos que agrupar todas as nossas palavras em uma fatia quando chamamos a join
função. Isso pode dificultar a leitura do código.
Agora, vamos escrever a mesma função, mas usaremos uma função variável:
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:
Sammy,Jessica,Drew,Jamie
Sammy,Jessica
Sammy
Enquanto ambas as versões da join
funçã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:
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 values
parâmetro em primeiro lugar na join
função. Isso causará o seguinte erro de compilação:
./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 join
função da última seção para ver o que acontece:
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:
./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 ...string
em 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:
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 join
função, explodimos a names
fatia anexando elipses ( ...
).
Isso permite que o programa seja executado agora como esperado:
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:
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
}
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
Introdução O MTA-STS (Security Strict Transport Security) do Mail Transport Agent é um novo...
Introdução Paginação é o conceito de restringir o número de linhas retornadas em um conjunto de...
Introdução O Ruby on Rails é uma estrutura de aplicativo da web popular do lado do servidor, com...
Introdução No Node.js, um módulo é uma coleção de funções e objetos JavaScript que podem ser...
Introdução Até o momento, em nossa série Como codificar no Go , você usou o comando go runpara...