O paradigma orientado a objetos traz boas vantagens, como, reutilização de código, legibilidade e manutenibilidade do código, natural modularização e produção de código mais acessível, já que as estruturas criadas geralmente representam aspectos também existentes no mundo real, nesse artigo iremos falar sobre a orientação a objetos na linguagem Go.
Quando lidamos com o paradigma orientado a objetos, acabamos criando diversas unidades de software através de estruturas chamadas classes. A partir destas classes, podemos criar estruturas chamadas objetos, estruturas estas que interagem entre si. Esse é o motivo pelo qual o paradigma é chamado de orientação a objetos: todas as interações necessárias para que o software funcione ocorrem por mensagens e comandos trocados entre estes objetos.
Caso você esteja iniciando e não conheça muita coisa sobre orientação a objetos, indico primeiramente a leitura do artigo “Os pilares da orientação a objetos”.
Curso Projeto de Banco de dados - Fundamentos
Conhecer o cursoMas a linguagem Go suporta o paradigma orientado a objetos?
Essa pergunta é um tanto quanto polemica, algumas pessoas irão responder que não, outras irão responder que sim e algumas vão responder que depende. Mas aqui vamos utilizar o posicionamento da própria Google em relação a essa pergunta.
No FAQ (Frequently Asked Questions), existe um tópico dedicado a essa questão. Eles dizem que a Golang possui um suporte limitado a orientação a objetos, ou seja, a linguagem possui suporte a orientação a objetos, porém, não da mesma maneira que estamos acostumados em outras linguagens.
Structs, as classes do Go
Quando falamos de orientação a objetos na linguagem Go, nós não temos o conceito de classes como estamos acostumados, o que existe no Go são as structs.
Em Go, as structs são tipos de dados compostos que permitem agrupar diferentes tipos de valores relacionados em um único objeto. Uma struct em Go é definida usando a palavra-chave type
seguida pelo nome da struct e uma lista de campos, que consistem em um nome e um tipo. Por exemplo:
type Pessoa struct {
Nome string
Idade int
Email string
}
Nesse exemplo, criamos uma struct chamada Pessoa
que possui três campos: Nome
, Idade
e Email
. Cada campo tem um tipo específico, como string
e int
.
Veja que as structs podem ser diretamente relacionadas com as classes da orientação a objetos, essa forma de agregar diretamente tipos de dados para formar um novo dado pode ser relacionado diretamente com uma classe e seus atributos.
Instanciando Structs
Uma vez que uma struct é definida, podemos criar variáveis desse tipo, preenchê-las com valores e acessar os campos usando a notação de ponto. Por exemplo:
func main() {
pessoa := Pessoa{
Nome: "João",
Idade: 25,
Email: "joao@example.com",
}
fmt.Println("Nome:", pessoa.Nome)
fmt.Println("Idade:", pessoa.Idade)
fmt.Println("Email:", pessoa.Email)
}
Neste exemplo, criamos uma variável pessoa
do tipo Pessoa
e atribuímos valores aos seus campos usando a sintaxe de inicialização de struct. Em seguida, podemos acessar os campos da struct usando a notação de ponto.
No Go não temos a mesma ideia de método construtor como temos nas classes, nós devemos informar quais os “atributos” da struct queremos atribuir seus respectivos valores.
As structs em Go são tipos por valor, o que significa que quando atribuímos uma struct a outra variável ou passamos uma struct como argumento para uma função, ocorre uma cópia dos valores dos campos. No entanto, também é possível trabalhar com ponteiros para structs se quisermos modificar o valor original da struct em uma função ou compartilhá-la eficientemente entre diferentes partes do código.
Pointer receivers, os métodos do Go
Curso Go Básico
Conhecer o cursoNa orientação a objetos as classes possuem dois recursos principais, os atributos e os métodos. Sendo que geralmente associamos os atributos como características da classe e os métodos como comportamentos da classe.
Até o momento vimos que com as structs podemos facilmente ter o mesmo comportamento de uma classe com os seus atributos, mas como ficam os métodos?
No Go podemos utilizar um recurso chamado de pointer receivers (ponteiro receptor) para termos o mesmo comportamento de uma método.
Em Go, os “pointer receivers” são um conceito relacionado aos métodos definidos em structs (ou tipos personalizados). Um “receiver” é um parâmetro especial de um método que define em qual tipo o método é definido e como ele pode ser chamado.
Existem dois tipos de receivers em Go: “value receivers” (receptores de valor) e “pointer receivers” (receptores de ponteiro). Quando um método é definido com um “pointer receiver”, isso significa que o método opera no ponteiro para a instância da struct em vez de uma cópia do valor. Isso permite que o método modifique diretamente o valor original da struct.
Criando e usando os pointer receivers
Para entender melhor, vamos considerar um exemplo com uma struct chamada Pessoa
que possui um método definido com um “pointer receiver”:
type Pessoa struct {
Nome string
Idade int
}
func (p *Pessoa) AtualizarIdade(novaIdade int) {
p.Idade = novaIdade
}
Neste exemplo, definimos um método chamado AtualizarIdade
na struct Pessoa
. Observe que o receiver p
é um ponteiro para a struct Pessoa
. Isso indica que o método AtualizarIdade
opera diretamente no valor da struct referenciada pelo ponteiro.
Agora podemos criar uma instância da struct Pessoa
e chamar o método AtualizarIdade
:
func main() {
pessoa := Pessoa{
Nome: "Maria",
Idade: 30,
}
fmt.Println("Idade antes da atualização:", pessoa.Idade)
pessoa.AtualizarIdade(35)
fmt.Println("Idade após a atualização:", pessoa.Idade)
}
Neste exemplo, criamos uma variável pessoa
do tipo Pessoa
e atribuímos valores aos seus campos. Em seguida, chamamos o método AtualizarIdade
na variável pessoa
, passando o novo valor da idade como argumento. Como o método é um “pointer receiver”, ele pode modificar diretamente o valor do campo Idade
na instância da struct original.
Portanto, ao executar o código acima, o valor do campo Idade
da struct pessoa
é atualizado para 35.
É importante observar que, ao chamar um método com um “pointer receiver”, Go permite que você chame o método diretamente em um ponteiro para a struct (como pessoa.AtualizarIdade(35)
) ou em uma variável do tipo da struct (como (&pessoa).AtualizarIdade(35)
). Ambas as formas são equivalentes e o compilador de Go faz a conversão implicitamente quando necessário.
O uso de “pointer receivers” é útil quando você precisa modificar o valor original da struct dentro de um método. Isso evita a cópia desnecessária de dados e permite maior eficiência e flexibilidade na manipulação dos valores.
Conclusão
Em conclusão, mesmo que a linguagem Go não siga o paradigma orientado a objetos da mesma forma que outras linguagens, ela oferece suporte limitado a esse paradigma por meio do uso de structs e pointer receivers.
As structs do Go podem ser comparadas às classes, permitindo agrupar diferentes tipos de valores relacionados em um único objeto. Com as structs, podemos criar variáveis, preenchê-las com valores e acessar seus campos. Além disso, os pointer receivers permitem definir métodos que operam diretamente no valor original da struct, proporcionando comportamentos semelhantes aos métodos de uma classe.
Assim, embora Go possua uma abordagem única para a orientação a objetos, é possível obter benefícios semelhantes, como reutilização de código e modularização, por meio desses recursos da linguagem.
Por fim, caso queira aprender mais sobre a Go e sua infinidade de recursos saiba que aqui na TreinaWeb temos o curso Go Básico que possui 05h30 de vídeo e um total de 37 exercícios.
Veja quais são os tópicos abordados durante o curso Go Básico:
- Compreender a sintaxe básica da Golang;
- Compreender conceitos básicos envolvidos na Go, como ponteiros de memória;
- Utilizar as estruturas básicas da linguagem, como declaração de variáveis;
- Utilizar as principais estruturas de conjuntos da Go, como arrays, slices e maps;
- Entender as principais funções na Golang que são built-in, como make(), new(), panic(), recover() e defer;
- Organizar o código em pacotes e utilizar os principais pacotes disponibilizados pela linguagem;
- Entender como podemos utilizar concorrência com a Golang, inclusive com técnicas como os channels;
- Entender o que são as structs na Go e como podemos utilizar um pouco de orientação a objetos com a linguagem;
- Realizar operações de I/O no sistema operacional, como a criação e escrita de arquivos.