Estou com três projetos de GO em mente, mas com medo de terminá-los. Quero fazer e ter a sensação de que estou aprendendo no processo, ao invés de só copiar e colar códigos de stackoverflow e chatgpt.
Eu quero dissecar os códigos, os conceitos e as ideias dos projetos para explicar em algum artigo, tipo esse. Acredito que assim eu conseguiria absorver bem o conhecimento por trás da produção dos códigos dos projetos.
Dos três projetos, nenhum se mostra ser algo muito simples. Então pensei em construir um quarto projeto, mais simples, mais curto e que eu consiga aprender alguma coisa.
Alguma coisa é melhor do que nada. E nada é melhor do que qualquer coisa inacabada.
Mas enfim, vamos nessa!
FCAT?
Ah, o nome é zuado mesmo, mas pensei no conceito de f-string, onde você introduz uma string em algum código.
Quanto ao gato... bem, aí você me pegou. As pessoas gostam de gatos. Somado a isso pensei que Nietzsche seria um gato, ao invés de um cachorro, uma borboleta, um elefante, um dinossauro ou um bicho preguiça. Então é isso. É gato, porque SIM.
Qual é o problema?
Começamos com o fato de já termos um arquivo txt com as citações do Nitzsche. O programa precisa selecionar alguma destas, de maneira aleatória e disponibilizar ao usuário. Além disso, precisa imprimir o gato em ASCII e formar um balão de diálogo em volta do quote exibido.
Resumindo:
Arquivo com as citações: arquivo .txt com citações do Nietzsche, onde cada citação esteja em uma linha separada.
Desenho de gato em ASCII: Vamos definir o desenho do gato que será impresso no terminal.
Gostei desse. Tem olhos hipnotizantes.
,_ _
|\\_,-~/
/ _ _ | ,--.
( @ @ ) / ,-'
\ _T_/-._( (
/ `. \
| _ \ |
\ \ , / |
|| |-_\__ /
((_/`(____,-'
Carregar e selecionar uma citação aleatória: O programa vai ler as citações de um arquivo .txt e selecionar uma aleatoriamente.
Imprimir a citação com o balão de diálogo: A citação será exibida dentro de um balão de diálogo acima do gato.
Letes go, bebê
Antes de mais nada:
Crie um diretório para o projeto e navegue até ele:
mkdir fcat
cd fcat
Crie um arquivo main.go:
touch main.go
Inicialize os módulos do go:
go mod init main.go
Seu diretório deverá estar tipo assim:
fcat
.
├── go.mod
├── main.go
└── quotes.txt
Agora abra o main.go em sua IDE de preferência.
NVIM se for do hype XD
Explicação do código:
Função carregarCitations
Essa função abre o arquivo de citações (nietzsche.txt), lê cada linha, e armazena todas as citações em uma lista.
A função não irá receber argumentos, apenas retornará uma lista/slice de strings e erro: string
e error
:
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations()([]string, error) {
}
Dentro da função iremos inicializar um slice/lista para receber todas as citações:
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations() ([]string, error) {
// Abrir uma lista para receber as citações
var citas []string
}
Agora, vamos abrir o arquivo txt:
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations() ([]string, error) {
// Abrir uma lista para receber as citações
var citas []string
// Abrir o arquivo txt com as citações
arquivo, err := os.Open('quotes.txt')
if err != nil {
return nil, err // Retorna erro se falhar em abrir arquivo
}
defer arquivo.Close()
}
Agora, nós vamos precisar criar um "scanner"
para realizar a leitura do nosso arquivo de citações quotes.txt
.
Ele também precisara ler cada linha do arquivo.
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations() ([]string, error) {
// Abrir uma lista para receber as citações
var citas []string
// Abrir o arquivo txt com as citações
arquivo, err := os.Open('quotes.txt')
if err != nil {
return nil, err // Retorna erro se falhar em abrir arquivo
}
defer arquivo.Close()
// Criar scanner para leitura do arquivo txt
scanner := bufio.NewScanner(arquivo)
// Ler cada linha de cada arquivo
for scanner.Scan() {
linha := scanner.Text() // Obter o texto da linha
citas = append(citas, linha) // Realiza a adição das linhas à lista/slice citas
}
}
Agora, faremos a verificação do erro na leitura do arquivo txt de citações e o retorno da nossa lista com as citações que foram adicionadas à mesma.
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations([]string, error) {
// Abrir uma lista para receber as citações
var citas []string
// Abrir o arquivo txt com as citações
arquivo, err := os.Open('quotes.txt')
if err != nil {
return nil, err // Retorna erro se falhar em abrir arquivo
}
defer arquivo.Close()
// Criar scanner para leitura do arquivo txt
scanner := bufio.NewScanner(arquivo)
// Ler cada linha de cada arquivo
for scanner.Scan() {
linha := scanner.Text() // Obter o texto da linha
citas = append(citas, linha) // Realiza a adição das linhas à lista citas
}
// Verifica se houve erro na leitura do arq txt
if err := scanner.Err(); err != nil {
return nil, err
}
// Retornar nossa lista com citações
return citas, nil // Retorna lista de citações
}
Agora precisamos criar a função main
para retornar as citações e verificar se a função carregarCitations
está correta:
func main() {
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações", err)
return
}
for _, citation := range citations {
fmt.Println(citation)
}
}
O código deve estar assim:
package main
import (
"fmt"
"os"
"bufio"
)
func carregarCitations([]string, error) {
// Abrir uma lista para receber as citações
var citas []string
// Abrir o arquivo txt com as citações
arquivo, err := os.Open('quotes.txt')
if err != nil {
return nil, err // Retorna erro se falhar em abrir arquivo
}
defer arquivo.Close()
// Criar scanner para leitura do arquivo txt
scanner := bufio.NewScanner(arquivo)
// Ler cada linha de cada arquivo
for scanner.Scan() {
linha := scanner.Text() // Obter o texto da linha
citas = append(citas, linha) // Realiza a adição das linhas à lista citas
}
// Verifica se houve erro na leitura do arq txt
if err := scanner.Err(); err != nil {
return nil, err
}
// Retornar nossa lista com citações
return citas, nil // Retorna lista de citações
}
func main() {
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações", err)
return
}
for _, citation := range citations {
fmt.Println(citation)
}
}
Agora vamos executar o código no terminal
go run main.go
Você deve visualizar todas as citações do seu arquivo quotes.txt em seu terminal.
Função getRandomCitation
Essa função usa a biblioteca math/rand
para selecionar uma citação aleatória da lista.
Dentro dos parênteses da função ()
, você define os parâmetros que a função recebe como entrada. No exemplo:
-
citations []string
significa que a funçãogetRandomCitation
espera um argumento chamado citations, que é um slice de strings (ou seja, uma lista de strings).
func getRandomCitation(citations []string
-
[]string
é a sintaxe de Go para dizer "uma fatia de strings", ou seja, uma coleção ordenada de strings.
Quando você chama a função, você deve passar uma lista de citações (por exemplo, carregada do arquivo quotes.txt), e essa lista será usada dentro da função.
Após os parênteses de entrada, logo antes do corpo da função {}, você especifica o tipo de valor que a função vai retornar.
-
string
logo após os parênteses significa que a função vai retornar uma string quando terminar de executar.
func getRandomCitation(citations []string) string {
Neste caso, a função vai retornar uma citação aleatória, que é uma única string.
Entretanto, precisamos gerar um valor aleatório, mas REALMENTE aleatório. Se utilizarmos somente rand.Seed()
, a semente padrão será sempre a mesma. Por isso precisamos passar como parâmetros, outras duas funções:
time.Now(),
que retorna o horário atualUnixNano()
, que converterá esse horário em um número inteiro, representando a quantidade de nanosegundos desde 1 de janeiro de 1970. A alta granularidade que é o pulo do gato XD
E depois precisamos que a função retorne um índice aleatório de citations de acordo com o tamanho da lista de citações (length)
import (
"math/rand" // Não esqueça de incluir essa biblioteca
"time" // Não esqueça de incluir essa biblioteca
)
func getRandomCitation(citations []string) string {
// Inicializa um número aleatório
rand.Seed(time.Now().UnixNano())
// Seleciona um índice aleatório de citations
randomIndex := rand.Intn(len(citations))
// Retorna uma citação aleatória
return cictaions[randomIndex]
}
len(citations)
retorna o número de citações no slice.rand.Intn(n)
gera um número aleatório entre 0 e n-1.rand.Intn(len(citations))
seleciona um índice aleatório válido para acessar uma citação da lista.
E agora vamos alterar a função main, para imprimirmos a citação aleatória:
func main() {
// Chama função para carregar as citações
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações:", err)
return
}
// Obtém uma citação aleatória de citations utilizando a função getRandomCitation
randomCitation := getRandomCitation(citations)
// Imprime a citação aleatória
fmt.Println("Citação aleatória", randomCitation)
O nosso código deve estar assim:
package main
import (
"bufio"
"fmt"
"os"
"math/rand"
"time"
)
// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
// Iniciar uma lista para receber todas as citações
var citas []string
// Abrir arquivo txt
arquivo, err := os.Open("quotes.txt")
if err != nil {
return nil, err // Retorna erro se falhar ao abrir o arquivo txt
}
defer arquivo.Close() // Garante o fechamento do arquivo ao final
// Iniciar um scanner para leitura do arquivo
scanner := bufio.NewScanner(arquivo)
// Ler cada linha do arquivo txt
for scanner.Scan() {
linha := scanner.Text()
citas = append(citas, linha)
}
// Verifica se houve algum erro durante a leitura do arquivo
if err := scanner.Err(); err != nil {
return nil, err
}
return citas, nil // Retorna lista de citações
}
func getRandomCitation(citations []string) string {
// Inicializa o gerado de numero aleatório
rand.Seed(time.Now().UnixNano())
// Seleciona um índice aleatório
randomIndex := rand.Intn(len(citations))
// Retornar uma citação aleatório
return citations[randomIndex]
}
func main() {
// Chama a função para cerregar citações
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações:", err)
return
}
// Obtém uma citação aleatória de citations utilizando a função getRandomCitation
randomCitation := getRandomCitation(citations)
// Imprime a citação aleatória
fmt.Println("Citação aleatória:", randomCitation)
}
Agora rode o main.go
em seu terminal a fim de verificar se conseguimos uma citação aleatória:
go rum main.go
Função imprimirGato
Essa função exibe o desenho de um gato em ASCII e imprime a citação dentro de um balão de diálogo.
func imprimirGato(citacao string) {
tamanhoBalao := len(citacao)
linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
linhaCitacao := fmt.Sprintf("| %s |", citacao)
linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)
// Imprime o balão de diálogo
fmt.Println(linhaTopo)
fmt.Println(linhaCima)
fmt.Println(linhaCitacao)
fmt.Println(linhaBaixo)
fmt.Println(linhaBase)
// Imprime o desenho do gato em ASCII com barras escapadas corretamente
fmt.Println(` \
\
,_ _
|\\_,-~/
/ _ _ | ,--.
( @ @ ) / ,-'
\ _T_/-._( (
/ \. \
| _ \ |
\ \ , / |
|| |-_\__ /
((_/` + "`(____,-'`)")
}
Função main
Na função main()
, o programa carrega as citações, seleciona uma aleatória e imprime o gato com a citação em um balão.
func main() {
// Carregar as citações do arquivo
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações:", err)
return
}
// Obter uma citação aleatória
randomCitation := getRandomCitation(citations)
// Imprimir o balão com o gato e a citação aleatória
imprimirGato(randomCitation)
}
Nosso código final deve estar assim:
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strings"
"time"
)
// Função para carregar citações do arquivo quotes.txt
func carregarCitations() ([]string, error) {
var citas []string
arquivo, err := os.Open("quotes.txt")
if err != nil {
return nil, err
}
defer arquivo.Close()
scanner := bufio.NewScanner(arquivo)
for scanner.Scan() {
linha := scanner.Text()
citas = append(citas, linha)
}
if err := scanner.Err(); err != nil {
return nil, err
}
return citas, nil
}
func getRandomCitation(citations []string) string {
rand.Seed(time.Now().UnixNano())
randomIndex := rand.Intn(len(citations))
return citations[randomIndex]
}
func imprimirGato(citacao string) {
tamanhoBalao := len(citacao)
linhaTopo := " " + strings.Repeat("-", tamanhoBalao+2)
linhaCima := "/" + strings.Repeat(" ", tamanhoBalao+2) + "\\"
linhaCitacao := fmt.Sprintf("| %s |", citacao)
linhaBaixo := "\\" + strings.Repeat(" ", tamanhoBalao+2) + "/"
linhaBase := " " + strings.Repeat("-", tamanhoBalao+2)
// Imprime o balão de diálogo
fmt.Println(linhaTopo)
fmt.Println(linhaCima)
fmt.Println(linhaCitacao)
fmt.Println(linhaBaixo)
fmt.Println(linhaBase)
// Imprime o desenho do gato em ASCII com barras escapadas corretamente
fmt.Println(` \
\
,_ _
|\\_,-~/
/ _ _ | ,--.
( @ @ ) / ,-'
\ _T_/-._( (
/ \. \
| _ \ |
\ \ , / |
|| |-_\__ /
((_/` + "`(____,-'`)")
}
func main() {
citations, err := carregarCitations()
if err != nil {
fmt.Println("Erro ao carregar citações:", err)
return
}
randomCitation := getRandomCitation(citations)
imprimirGato(randomCitation)
}
Finalizando
Agora nos resta compilar nosso programa e executar.
Compile seu arquivo main.go como fcat:
go build -o fcat main.go
E por fim, execute:
./fcat
O resultado foi esse:
------------------------------------------------------
/ \
| He who has a why to live for can bear almost any how |
\ /
------------------------------------------------------
\
\
,_ _
|\\_,-~/
/ _ _ | ,--.
( @ @ ) / ,-'
\ _T_/-._( (
/ \. \
| _ \ |
\ \ , / |
|| |-_\__ /
((_/`(____,-'`)
Achei interessante como algo tão simples pode se tornar tão complicado de executar.
Mas o que me impressionou foi a frase de saída do programa: "He who has a why to live for can bear almost any how"
Que a frase acima lhe inspire a continuar aprendendo.
REPO: https://github.com/ionnss/fcat
ions,
Mais um dia na terra