Desbravando o Go: Funções (parte 3)

Rafael Tardivo
rafaeltardivo
Published in
3 min readFeb 2, 2019

Como funcionam as funções em Go.

Já falamos sobre funções em Python e hoje falaremos sobre funções em Go!

Keyword func e chaves

Vamos novamente analisar o “Hello, World!” do primeiro post da série:

func main() {
fmt.Printf("Hello, World!\n")
}

observe que se trata de uma função. Em Go, funções são caracterizadas pela keyword func. Chaves também são obrigatórias! (saudades, Python!).

Até aí tudo bem, certo? main não tem nenhuma parâmetro e também não retorna nada.

Funções com retorno de valores

Mas e se precisássemos retornar valores? Como ficaria?

Vamos usar como exemplo uma função que nos retorna uma string contendo o nosso bom e velho “Hello, World!”, chamaremos ela de sayHello:

func sayHello() string{
return "Hello, World!"
}

Observe que agora foi necessário incluir string logo após os parênteses, na assinatura da função. A declaração em questão também é obrigatória, pois é ela quem determina o tipo do retorno da função.

Retornando múltiplos valores

Em Go também é possível retornar múltiplos valores! Basta declarar também o segundo tipo de retorno:

func multipleValues() string, int{
return "Foo", 42
}

Funções com parâmetros

Parâmetros em Go são declarados da mesma maneira que em outras linguagens: dentro dos parênteses que sucedem o nome da função (juntamente com o seu respectivo tipo):

func sumTwoNumbers(numOne int, numTwo int) int{
return numOne + numTwo
}

Passagem de argumentos: valor ou referência?

Em Go, assim como em C, temos ponteiros! Isso quer dizer que existe passagem por referência? NÃO.

Todas as passagens em Go são por valor! O que acontece é que quando passamos um “ponteiro”, passamos a cópia do valor do endereço de um objeto, enquanto quando passamos um “valor”, passamos uma cópia do valor daquele endereço. Vamos ver na prática

Cópia do valor

package mainimport "fmt"type pet struct {
name string
}
func changeName(p pet) {
p.name = "Nina"
fmt.Println("During the call", p.name)
}
func main() {
pluto := pet{name: "Pluto"}
fmt.Println("Before the call", pluto.name)
changeName(pluto)
fmt.Println("After the call", pluto.name)
}

A saída do trecho acima será:

Before the call Pluto
During the call Nina
After the call Pluto

Isso porque passamos uma cópia da struct pet! A alteração durante a função só afeta a struct cópia.

Cópia do endereço (ponteiro)

Já se passarmos a struct como ponteiro, a cópia do endereço fará com que ela seja alterada fora do escopo da função, causando o efeito de “passagem por referência”:

package mainimport "fmt"type pet struct {
name string
}
func changeName(p *pet) {
p.name = "Nina"
fmt.Println("During the call", p.name)
}
func main() {
pluto := pet{name: "Pluto"}
fmt.Println("Before the call", pluto.name)
changeName(&pluto)
fmt.Println("After the call", pluto.name)
}

Observe que dessa vez a saída será algo como:

Before the call Pluto
During the call Nina
After the call Nina

Então é isso aí! Atenção aos detalhes e particularidades da linguagem!

Cya ;)

--

--