Usando sistema de tipos em funções no Go
Olá leitor, seja bem vindo a mais uma lição da jornada GoLang 🥳
Durante sua jornada como desenvolvedor de sistemas em Go, você vai se deparar com funções que implementam e recebem diversos tipos básicos, compostos e até tipos mais avançados.
O objetivo desta lição, é te ensinar a como mesclar todos os tipos que você já aprendeu até aqui, com o uso de funções e métodos em Go.
Vamos nessa?
Criando seu projeto de testes
Dentro da pasta JornadaGoLang, nós iremos criar uma nova pasta chamada de 12-sistemas-de-tipos-com-funcoes
, onde dentro dela, vamos criar o nosso arquivo main.go
:
package main
func main(){
}
Agora, vamos começar pelos tipos básicos 😉
Funções com Tipos Básicos
Na lição que falava sobre tipos básicos, você aprendeu que a linguagem GoLang possuí diversos tipos como: int
, float64
, string
, bool
, entre outros
E como você já deve saber, é possível criar uma função que não só seja capaz de receber tais tipos (dentro de variáveis temporárias), como também retorná-los:
package main
import "fmt"
func soma(a int, b int) int {
return a + b
}
func main() {
resultado := soma(10, 5)
fmt.Println("Soma:", resultado)
}
No código acima, criamos uma variável chamada resultado
, que recebe dois tipos inteiros e retorna um inteiro.
Funções com Tipos Compostos (Array e Slice)
Na lição que falava sobre tipos compostos, você aprendeu que a linguagem possuí apenas três deles: array
, slice
e map
.
Tais tipos podem ser recebidos por uma função, observe:
package main
import "fmt"
func somaElementos(numeros []int) int {
total := 0
for _, num := range numeros {
total += num
}
return total
}
func main() {
numeros := []int{1, 2, 3, 4, 5}
fmt.Println("Soma dos elementos:", somaElementos(numeros))
}
No código acima, criamos uma função chamada somaElementos
que recebe um slice
de números inteiros e retorna um valor inteiro.
Além disso, você pode retornar um array
ou um slice
caso desejar:
package main
import "fmt"
// RetornaSlice recebe dois números e os retorna em um slice.
func RetornaSlice(a, b int) []int {
return []int{a, b}
}
func main() {
numeros := RetornaSlice(10, 20)
fmt.Println("Slice retornado:", numeros)
}
No caso de um map
, podemos utilizá-los como parâmetros de retornos de funções da seguinte forma:
package main
import "fmt"
func contarPalavras(texto string) map[rune]int {
contagem := make(map[rune]int)
for _, letra := range texto {
contagem[letra]++
}
return contagem
}
func main() {
resultado := contarPalavras("banana")
fmt.Println("Frequência das letras:", resultado)
}
No código acima, estamos recebendo uma string
, e retornando um map
. Nós também podemos receber um map
da mesma forma como fizemos acima no exemplo do uso de uma slice
e um array
:
package main
import "fmt"
// MapParaString recebe um map de string para string e retorna uma representação em formato de texto.
func MapParaString(m map[string]string) string {
resultado := ""
for chave, valor := range m {
resultado += fmt.Sprintf("%s: %s\n", chave, valor)
}
return resultado
}
func main() {
dados := map[string]string{
"Nome": "Carlos",
"Idade": "30",
"Cidade": "São Paulo",
}
resultado := MapParaString(dados)
fmt.Println("String gerada:\n", resultado)
}
Funções com Structs
Na lição que falava sobre tipos avançados em Go, você aprendeu a utilizar uma struct
, certo?
Sendo assim, saiba que nós podemos definir funções que trabalham com structs
, de forma a encapsular dados e comportamentos, observe:
package main
import "fmt"
type Pessoa struct {
Nome string
Idade int
}
func (p Pessoa) Saudacao() string {
return fmt.Sprintf("Olá, meu nome é %s e tenho %d anos.", p.Nome, p.Idade)
}
func main() {
pessoa := Pessoa{"Carlos", 30}
fmt.Println(pessoa.Saudacao())
}
Além disso, podemos receber um conjunto de tipos básicos e retornar em um formato de struct
:
package main
import "fmt"
// Pessoa representa uma estrutura com nome, idade e cidade.
type Pessoa struct {
Nome string
Idade int
Cidade string
}
// NovaPessoa recebe valores básicos e retorna uma struct Pessoa.
func NovaPessoa(nome string, idade int, cidade string) Pessoa {
return Pessoa{
Nome: nome,
Idade: idade,
Cidade: cidade,
}
}
func main() {
pessoa := NovaPessoa("Ana", 28, "Rio de Janeiro")
fmt.Printf("Pessoa: %+v\n", pessoa)
}
Métodos com Ponteiros
Apesar de não termos entrado neste assunto ainda, é possível criar métodos que fazem uso de ponteiros em Go:
package main
import "fmt"
type Contador struct {
Valor int
}
func (c *Contador) Incrementar() {
c.Valor++
}
func main() {
c := Contador{Valor: 0}
c.Incrementar()
fmt.Println("Valor do contador:", c.Valor)
}
Funções com Interfaces
Ainda na lição de tipos avançados em Go, também é possível implementar interfaces por meio de funções genéricas:
package main
import "fmt"
type Forma interface {
Area() float64
}
type Quadrado struct {
Lado float64
}
func (q Quadrado) Area() float64 {
return q.Lado * q.Lado
}
type Circulo struct {
Raio float64
}
func (c Circulo) Area() float64 {
return 3.14 * c.Raio * c.Raio
}
func imprimirArea(f Forma) {
fmt.Println("Área da forma:", f.Area())
}
func main() {
q := Quadrado{Lado: 4}
c := Circulo{Raio: 3}
imprimirArea(q)
imprimirArea(c)
}
É possível criar uma função em GoLang que retorna uma interface?
Sim! Em Go, é totalmente possível criar uma função que retorne uma interface. Isso é útil quando você deseja que a função retorne diferentes tipos que implementam um comportamento comum.
Vejamos um exemplo:
package main
import "fmt"
// Interface Forma define um comportamento comum.
type Forma interface {
Area() float64
}
// Estrutura Quadrado
type Quadrado struct {
Lado float64
}
// Método Area() para Quadrado (implementa Forma)
func (q Quadrado) Area() float64 {
return q.Lado * q.Lado
}
// Estrutura Circulo
type Circulo struct {
Raio float64
}
// Método Area() para Circulo (implementa Forma)
func (c Circulo) Area() float64 {
return 3.14 * c.Raio * c.Raio
}
// NovaForma retorna uma interface Forma com base no tipo.
func NovaForma(tipo string, valor float64) Forma {
if tipo == "quadrado" {
return Quadrado{Lado: valor}
}
return Circulo{Raio: valor}
}
func main() {
forma := NovaForma("quadrado", 5)
fmt.Println("Área da forma:", forma.Area())
outraForma := NovaForma("circulo", 3)
fmt.Println("Área da outra forma:", outraForma.Area())
}
Incrível, não acha? 😉
Uso de interface{} e Generics
Como você viu na lição passada, a partir do Go 1.18+, podemos usar generics
para criar funções que operam em múltiplos tipos, e isso também pode se aplicar a funções:
package main
import "fmt"
func Soma[T int | float64](a, b T) T {
return a + b
}
func main() {
fmt.Println(Soma(10, 20)) // Inteiros
fmt.Println(Soma(5.5, 2.3)) // Floats
}
Repositório da lição
Todos os arquivos relacionados com esta lição, podem ser encontrados nos seguintes repositórios abaixo:
Conclusão
Sim, está lição foi bem básica, e talvez nem tenha dado tempo de se aquecer 😩
A ideia desta lição foi justamente sintetizar e mesclar os conteúdos que aprendemos nas lições de:
Até a próxima 🤖