Go

O que Todo Dev Deve Saber sobre Pacote fmt em Go: Formatação, Verbos e Strings Avançadas

21 min de leitura

O que Todo Dev Deve Saber sobre Pacote fmt em Go: Formatação, Verbos e Strings Avançadas

Introdução ao Pacote fmt: Fundamentos e Importância O pacote é um dos pilares da linguagem Go, responsável pela formatação e impressão de dados. Seu nome vem de "format" e oferece funções que permitem controlar como valores são exibidos, sejam eles números, strings, estruturas ou tipos customizados. Diferentemente de linguagens como Python que usam f-strings ou C que utiliza printf, Go oferece uma abordagem elegante através de verbos de formato específicos que você precisa dominar. A razão pela qual este pacote é tão importante está em sua ubiquidade. Praticamente todo programa Go que gera saída o utiliza, seja para debug, logs ou apresentação de dados ao usuário. Compreender profundamente seus mecanismos não apenas torna seu código mais legível, mas também permite tratamento de erros mais adequado e otimização de performance em operações de formatação intensivas. Este artigo guiará você desde os conceitos básicos até técnicas avançadas que poucos desenvolvedores Go exploram completamente. Verbos de Formatação: O Coração do fmt Os Verbos

<h2>Introdução ao Pacote fmt: Fundamentos e Importância</h2>

<p>O pacote <code>fmt</code> é um dos pilares da linguagem Go, responsável pela formatação e impressão de dados. Seu nome vem de &quot;format&quot; e oferece funções que permitem controlar como valores são exibidos, sejam eles números, strings, estruturas ou tipos customizados. Diferentemente de linguagens como Python que usam f-strings ou C que utiliza printf, Go oferece uma abordagem elegante através de verbos de formato específicos que você precisa dominar.</p>

<p>A razão pela qual este pacote é tão importante está em sua ubiquidade. Praticamente todo programa Go que gera saída o utiliza, seja para debug, logs ou apresentação de dados ao usuário. Compreender profundamente seus mecanismos não apenas torna seu código mais legível, mas também permite tratamento de erros mais adequado e otimização de performance em operações de formatação intensivas. Este artigo guiará você desde os conceitos básicos até técnicas avançadas que poucos desenvolvedores Go exploram completamente.</p>

<h2>Verbos de Formatação: O Coração do fmt</h2>

<h3>Os Verbos Básicos e Seus Usos</h3>

<p>Um verbo de formato é um marcador que começa com <code>%</code> seguido de uma letra que especifica como um valor deve ser formatado. Go oferece uma variedade considerável, cada uma com um propósito específico. Os mais utilizados são <code>%v</code> para valor geral, <code>%d</code> para inteiros, <code>%s</code> para strings e <code>%f</code> para números de ponto flutuante. Compreender quando usar cada um é fundamental.</p>

<p>Vamos começar com um exemplo prático que demonstra os verbos mais comuns:</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Inteiros

fmt.Printf(&quot;Decimal: %d\n&quot;, 42) // Saída: Decimal: 42

fmt.Printf(&quot;Octal: %o\n&quot;, 42) // Saída: Octal: 52

fmt.Printf(&quot;Hexadecimal: %x\n&quot;, 42) // Saída: Hexadecimal: 2a

fmt.Printf(&quot;Hexadecimal maiúsculo: %X\n&quot;, 42) // Saída: Hexadecimal maiúsculo: 2A

fmt.Printf(&quot;Binário: %b\n&quot;, 42) // Saída: Binário: 101010

// Strings e caracteres

fmt.Printf(&quot;String: %s\n&quot;, &quot;Hello&quot;) // Saída: String: Hello

fmt.Printf(&quot;Caractere: %c\n&quot;, 65) // Saída: Caractere: A

fmt.Printf(&quot;Aspas: %q\n&quot;, &quot;Hello&quot;) // Saída: Aspas: &quot;Hello&quot;

// Números de ponto flutuante

fmt.Printf(&quot;Float padrão: %f\n&quot;, 3.14159) // Saída: Float padrão: 3.141590

fmt.Printf(&quot;Float científico: %e\n&quot;, 3.14159) // Saída: Float científico: 3.141590e+00

fmt.Printf(&quot;Float compacto: %g\n&quot;, 3.14159) // Saída: Float compacto: 3.14159

// Valor genérico

valor := 42

fmt.Printf(&quot;Valor genérico: %v\n&quot;, valor) // Saída: Valor genérico: 42

fmt.Printf(&quot;Tipo: %T\n&quot;, valor) // Saída: Tipo: int

}</code></pre>

<p>O verbo <code>%v</code> é especial porque tenta representar o valor de forma &quot;natural&quot; para seu tipo. Para inteiros, funciona como <code>%d</code>; para strings, como <code>%s</code>. Já <code>%T</code> mostra o tipo dinâmico, extremamente útil em debug. O verbo <code>%q</code> é particularmente interessante pois formata strings com escapes apropriados, útil para gerar código Go válido.</p>

<h3>Verbos Avançados e Comportamentos Especiais</h3>

<p>Além dos básicos, existem verbos menos conhecidos mas poderosos para casos específicos. O <code>%p</code> formata ponteiros em hexadecimal, <code>%U</code> formata runes no formato Unicode, e <code>%v</code> com flags consegue fazer muito mais. Cada verbo pode ser modificado com flags que alteram seu comportamento.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Ponteiros

x := 42

fmt.Printf(&quot;Ponteiro: %p\n&quot;, &amp;x) // Saída: Ponteiro: 0xc0000160d8 (endereço varia)

// Unicode

fmt.Printf(&quot;Rune: %U\n&quot;, &#039;Ω&#039;) // Saída: Rune: U+03A9

fmt.Printf(&quot;Caractere unicode: %c\n&quot;, 0x03A9) // Saída: Caractere unicode: Ω

// Booleanos

fmt.Printf(&quot;Booleano: %v\n&quot;, true) // Saída: Booleano: true

fmt.Printf(&quot;Booleano com verbo: %t\n&quot;, true) // Saída: Booleano com verbo: true

// Valores nil

var ptr *int

fmt.Printf(&quot;Nil: %v\n&quot;, ptr) // Saída: Nil: &lt;nil&gt;

fmt.Printf(&quot;Nil com tipo: %#v\n&quot;, ptr) // Saída: Nil com tipo: (*int)(nil)

}</code></pre>

<p>O modificador <code>#</code> (denominado &quot;flag de alternativa&quot;) muda o comportamento de certos verbos. Com <code>%#v</code>, obtém-se uma representação mais detalhada que inclui o tipo. Com <code>%#x</code>, adiciona o prefixo <code>0x</code>. Com <code>%#o</code>, adiciona o prefixo <code>0</code>. Isso é fundamental para gerar código Go válido ou representações mais claras.</p>

<h2>Flags, Largura e Precisão: Controle Fino</h2>

<h3>Compreendendo Flags e Largura</h3>

<p>Cada verbo pode ser precedido por flags que modificam seu comportamento. A flag <code>0</code> preenche com zeros, <code>-</code> alinha à esquerda em vez de à direita, <code>+</code> sempre mostra o sinal mesmo para positivos, e o espaço coloca um espaço em vez de sinal para positivos. A largura especifica o número mínimo de caracteres na saída.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Largura básica

fmt.Printf(&quot;Padrão: | %5d | \n&quot;, 42) // Saída: Padrão: | 42 fmt.Printf(&quot;Alinhado: |%-5d|\n&quot;, 42) // Saída: Alinhado: |42 | fmt.Printf(&quot;Zeros: |%05d|\n&quot;, 42) // Saída: Zeros: |00042|

// Sinais

fmt.Printf(&quot;Sem sinal: %d\n&quot;, 42) // Saída: Sem sinal: 42

fmt.Printf(&quot;Com sinal +: %+d\n&quot;, 42) // Saída: Com sinal +: +42

fmt.Printf(&quot;Espaço: % d\n&quot;, 42) // Saída: Espaço: 42

fmt.Printf(&quot;Negativo com +: %+d\n&quot;, -42) // Saída: Negativo com +: -42

// Combinações

fmt.Printf(&quot;Completo: | %+08d | \n&quot;, 42) // Saída: Completo: | +000042 fmt.Printf(&quot;Completo neg: |%+08d|\n&quot;, -42) // Saída: Completo neg: |-000042|

}</code></pre>

<p>A ordem das flags importa semanticamente. Go processa flags na ordem padrão, mas sua aplicação segue uma lógica específica: largura é sempre aplicada por último. Note que quando você usa <code>0</code> com <code>-</code>, a flag de zero é ignorada porque alinhar à esquerda é incompatível com preenchimento de zeros.</p>

<h3>Precisão para Strings e Floats</h3>

<p>A precisão, especificada após um ponto decimal (como em <code>%.3f</code>), tem significados diferentes dependendo do verbo. Para floats, especifica o número de casas decimais. Para strings, especifica o número máximo de caracteres a exibir. Para inteiros com <code>%d</code>, o comportamento é controlado por <code>0</code>.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Precisão em floats

fmt.Printf(&quot;Padrão: %f\n&quot;, 3.14159) // Saída: Padrão: 3.141590

fmt.Printf(&quot;2 casas: %.2f\n&quot;, 3.14159) // Saída: 2 casas: 3.14

fmt.Printf(&quot;0 casas: %.0f\n&quot;, 3.14159) // Saída: 0 casas: 3

fmt.Printf(&quot;5 casas: %.5f\n&quot;, 3.14159) // Saída: 5 casas: 3.14159

// Precisão em strings

fmt.Printf(&quot;Padrão: %s\n&quot;, &quot;Hello World&quot;) // Saída: Padrão: Hello World

fmt.Printf(&quot;Truncado: %.5s\n&quot;, &quot;Hello World&quot;) // Saída: Truncado: Hello

fmt.Printf(&quot;Com largura: %10.5s\n&quot;, &quot;Hello World&quot;) // Saída: Com largura: Hello

// Combinando largura e precisão

fmt.Printf(&quot;Float: | %8.2f | \n&quot;, 3.14159) // Saída: Float: | 3.14 fmt.Printf(&quot;String: |%10.5s|\n&quot;, &quot;Hello World&quot;) // Saída: String: | Hello|

}</code></pre>

<p>A combinação de largura e precisão é poderosa para gerar saídas formatadas profissionais. Note que a largura é aplicada ao resultado final após a precisão ser aplicada. Isso permite criar tabelas e relatórios estruturados com precisão.</p>

<h2>Funções de Saída e Manipulação de Strings Avançada</h2>

<h3>Println, Print, Printf e Sprintf</h3>

<p>Go oferece três principais famílias de funções no pacote fmt. A família <code>Print</code> (Print, Println) são mais simples e não usam verbos. A família <code>Printf</code> (Printf, Sprintf) usa verbos de formato. A distinção entre estas funções é crucial para diferentes contextos. <code>Println</code> adiciona espaços entre argumentos e uma quebra de linha; <code>Print</code> apenas concatena; <code>Printf</code> oferece controle total.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Print vs Println vs Printf

fmt.Print(&quot;Hello&quot;, &quot;World&quot;) // Saída: HelloWorld

fmt.Println(&quot;Hello&quot;, &quot;World&quot;) // Saída: Hello World\n

fmt.Printf(&quot;Hello %s\n&quot;, &quot;World&quot;) // Saída: Hello World\n

// Sprintf retorna a string sem exibir

resultado := fmt.Sprintf(&quot;Número: %d&quot;, 42)

fmt.Println(&quot;Resultado:&quot;, resultado) // Saída: Resultado: Número: 42

// Sprintln para gerar strings com quebras de linha

resultado2 := fmt.Sprintln(&quot;Um&quot;, &quot;Dois&quot;, &quot;Três&quot;)

fmt.Print(&quot;String gerada: |&quot; + resultado2 + &quot;|&quot;) // Note as quebras

// Aplicação prática: construir strings sem alocação excessiva

nome := &quot;Alice&quot;

idade := 30

mensagem := fmt.Sprintf(&quot;Olá, %s! Você tem %d anos.&quot;, nome, idade)

fmt.Println(mensagem) // Saída: Olá, Alice! Você tem 30 anos.

}</code></pre>

<p><code>Sprintf</code> é particularmente útil porque retorna a string formatada sem exibir, permitindo armazená-la para processamento posterior. Isso é mais eficiente do que concatenação manual de strings em Go, especialmente quando você precisa formatar múltiplos valores.</p>

<h3>Tratamento de Erros com Errorf</h3>

<p>A função <code>Errorf</code> combina formatação com criação de erros. Internamente, cria uma nova instância de <code>error</code> com a mensagem formatada, sendo extremamente útil para propagar erros com contexto apropriado.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

&quot;errors&quot;

)

func divide(a, b float64) (float64, error) {

if b == 0 {

// Errorf cria um erro com mensagem formatada

return 0, fmt.Errorf(&quot;divisão por zero: %f / %f&quot;, a, b)

}

return a / b, nil

}

func conectarServidor(host string, porta int) error {

// Simulando falha de conexão

if porta &lt; 1 || porta &gt; 65535 {

return fmt.Errorf(&quot;porta inválida %d para host %s&quot;, porta, host)

}

return nil

}

func main() {

// Testando divide

resultado, err := divide(10, 0)

if err != nil {

fmt.Println(&quot;Erro:&quot;, err) // Saída: Erro: divisão por zero: 10.000000 / 0.000000

}

// Testando conexão

err = conectarServidor(&quot;localhost&quot;, 99999)

if err != nil {

fmt.Println(&quot;Erro de conexão:&quot;, err) // Saída: Erro de conexão: porta inválida 99999 para host localhost

}

// Wrapping de erros (Go 1.13+)

originalErr := errors.New(&quot;falha na leitura&quot;)

wrappedErr := fmt.Errorf(&quot;falha ao processar arquivo: %w&quot;, originalErr)

fmt.Println(&quot;Erro wrappado:&quot;, wrappedErr) // Saída: Erro wrappado: falha ao processar arquivo: falha na leitura

}</code></pre>

<p>Note o uso de <code>%w</code> na última função. Este verbo especial (introduzido em Go 1.13) permite envolver erros mantendo a cadeia de erros intacta para <code>errors.Is()</code> e <code>errors.As()</code>. Sem <code>%w</code>, a cadeia seria perdida e causaria problemas em tratamento de erros mais sofisticado.</p>

<h3>Stringer Interface e Formatação Customizada</h3>

<p>Quando você implementa a interface <code>Stringer</code> (com método <code>String() string</code>), a função <code>fmt.Println</code> e o verbo <code>%v</code> usam automaticamente este método para representar seu tipo. Isso permite controle total sobre como seus tipos customizados são exibidos.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

type Pessoa struct {

Nome string

Idade int

Email string

}

// Implementando a interface Stringer

func (p Pessoa) String() string {

return fmt.Sprintf(&quot;Pessoa{Nome: %s, Idade: %d, Email: %s}&quot;, p.Nome, p.Idade, p.Email)

}

type Ponto struct {

X, Y float64

}

func (p Ponto) String() string {

return fmt.Sprintf(&quot;(%.2f, %.2f)&quot;, p.X, p.Y)

}

func main() {

// Sem Stringer, seria exibido com os nomes dos campos

pessoa := Pessoa{&quot;João&quot;, 25, &quot;joao@example.com&quot;}

fmt.Println(pessoa) // Saída: Pessoa{Nome: João, Idade: 25, Email: joao@example.com}

// Também funciona com Printf e %v

fmt.Printf(&quot;Pessoa: %v\n&quot;, pessoa) // Saída: Pessoa: Pessoa{Nome: João, Idade: 25, Email: joao@example.com}

// Para tipos simples

ponto := Ponto{3.14159, 2.71828}

fmt.Println(ponto) // Saída: (3.14, 2.72)

// %v usa String(), %#v não quando há Stringer

fmt.Printf(&quot;Com %%v: %v\n&quot;, ponto) // Saída: Com %v: (3.14, 2.72)

fmt.Printf(&quot;Com %%#v: %#v\n&quot;, ponto) // Saída: Com %#v: fmt.Ponto{X:3.14159, Y:2.71828}

}</code></pre>

<p>A implementação de <code>Stringer</code> é uma prática excelente para tipos estruturados. Torna debug mais simples e logs mais legíveis. Note que <code>%#v</code> bypassa o método <code>String()</code> e mostra a representação Go do valor, útil quando você precisa da representação literal em vez da customizada.</p>

<h2>Casos de Uso Avançados e Otimizações</h2>

<h3>Formatação de Slices e Mapas</h3>

<p>Go permite formatar coleções diretamente com <code>%v</code> ou <code>%#v</code>, mas cada um produz saída diferente. Entender essas diferenças é importante para debug eficaz.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

func main() {

// Slices

numeros := []int{1, 2, 3, 4, 5}

fmt.Printf(&quot;Slice com %%v: %v\n&quot;, numeros) // Saída: Slice com %v: [1 2 3 4 5]

fmt.Printf(&quot;Slice com %%#v: %#v\n&quot;, numeros) // Saída: Slice com %#v: []int{1, 2, 3, 4, 5}

// Mapas

config := map[string]int{&quot;porta&quot;: 8080, &quot;timeout&quot;: 30}

fmt.Printf(&quot;Map com %%v: %v\n&quot;, config) // Saída depende da ordem de iteração

fmt.Printf(&quot;Map com %%#v: %#v\n&quot;, config) // Saída inclui tipos

// Slices de structs

pessoas := []Pessoa{

{&quot;Alice&quot;, 30, &quot;alice@example.com&quot;},

{&quot;Bob&quot;, 25, &quot;bob@example.com&quot;},

}

fmt.Printf(&quot;Slice de structs: %v\n&quot;, pessoas)

fmt.Printf(&quot;Slice de structs #v: %#v\n&quot;, pessoas)

// Estrutura aninhada

type Config struct {

Banco map[string]string

Portas []int

}

cfg := Config{

Banco: map[string]string{&quot;usuario&quot;: &quot;admin&quot;, &quot;senha&quot;: &quot;secret&quot;},

Portas: []int{80, 443, 8080},

}

fmt.Printf(&quot;Estrutura complexa: %#v\n&quot;, cfg)

}

type Pessoa struct {

Nome string

Idade int

Email string

}

func (p Pessoa) String() string {

return fmt.Sprintf(&quot;%s (%d)&quot;, p.Nome, p.Idade)

}</code></pre>

<p>A representação de estruturas aninhadas com <code>%#v</code> é especialmente útil para reproduzir estruturas literalmente em código. Cópie a saída e terá código Go válido que pode ser compilado.</p>

<h3>Formatter Interface para Controle Total</h3>

<p>Além de <code>Stringer</code>, existe a interface <code>Formatter</code> que oferece controle ainda maior sobre como seu tipo é formatado. Qualquer verbo pode ser interceptado e processado customizadamente.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

)

type Cor struct {

R, G, B uint8

}

// Implementando fmt.Formatter para controle total

func (c Cor) Format(s fmt.State, verb rune) {

switch verb {

case &#039;v&#039;:

if s.Flag(&#039;#&#039;) {

fmt.Fprintf(s, &quot;Cor{R:%d, G:%d, B:%d}&quot;, c.R, c.G, c.B)

} else {

fmt.Fprintf(s, &quot;rgb(%d, %d, %d)&quot;, c.R, c.G, c.B)

}

case &#039;s&#039;:

// Exibe como string hexadecimal

fmt.Fprintf(s, &quot;#%02x%02x%02x&quot;, c.R, c.G, c.B)

case &#039;q&#039;:

// Exibe com aspas

fmt.Fprintf(s, &quot;\&quot;#%02x%02x%02x\&quot;&quot;, c.R, c.G, c.B)

default:

fmt.Fprintf(s, &quot;%%!%c(Cor=%#v)&quot;, verb, c)

}

}

func main() {

vermelho := Cor{255, 0, 0}

azul := Cor{0, 0, 255}

fmt.Printf(&quot;Padrão: %v\n&quot;, vermelho) // Saída: Padrão: rgb(255, 0, 0)

fmt.Printf(&quot;Com #: %#v\n&quot;, vermelho) // Saída: Com #: Cor{R:255, G:0, B:0}

fmt.Printf(&quot;Como string: %s\n&quot;, vermelho) // Saída: Como string: #ff0000

fmt.Printf(&quot;Com aspas: %q\n&quot;, azul) // Saída: Com aspas: &quot;#0000ff&quot;

// Verbos não suportados caem no default

fmt.Printf(&quot;Verbo não suportado: %d\n&quot;, vermelho)

}</code></pre>

<p>A interface <code>Formatter</code> recebe um <code>fmt.State</code> que oferece informações sobre flags, largura e precisão. Você pode chamar <code>s.Flag()</code> para verificar se uma flag foi setada e <code>s.Width()</code> e <code>s.Precision()</code> para obter valores. Esta é a forma mais poderosa de customização de formatação em Go.</p>

<h3>Performance e Alocações</h3>

<p>Ao trabalhar com formatação intensiva, é importante compreender as implicações de performance. <code>Sprintf</code> aloca memória para cada chamada, então em loops críticos pode ser problemático. Usar <code>strings.Builder</code> com <code>fmt.Fprintf</code> é mais eficiente.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

&quot;strings&quot;

)

func exemploIneficiente(nomes []string) string {

resultado := &quot;&quot;

for _, nome := range nomes {

resultado += fmt.Sprintf(&quot;- %s\n&quot;, nome) // Aloca a cada iteração

}

return resultado

}

func exemploEficiente(nomes []string) string {

var builder strings.Builder

for _, nome := range nomes {

fmt.Fprintf(&amp;builder, &quot;- %s\n&quot;, nome) // Evita alocações

}

return builder.String()

}

func main() {

nomes := []string{&quot;Alice&quot;, &quot;Bob&quot;, &quot;Carol&quot;, &quot;David&quot;}

// Ambos produzem o mesmo resultado, mas o segundo é mais eficiente

resultado1 := exemploIneficiente(nomes)

resultado2 := exemploEficiente(nomes)

fmt.Println(&quot;Resultado 1:&quot;)

fmt.Print(resultado1)

fmt.Println(&quot;\nResultado 2:&quot;)

fmt.Print(resultado2)

// Para verificação

if resultado1 == resultado2 {

fmt.Println(&quot;\nAmbas as saídas são idênticas!&quot;)

}

}</code></pre>

<p><code>strings.Builder</code> não realoca memória a cada <code>Fprintf</code>, acumulando eficientemente. Em loops que formatam milhares de linhas, esta técnica pode resultar em diferenças de performance significativas. <code>Builder</code> é otimizado especificamente para este padrão de construção de strings.</p>

<h2>Conclusão</h2>

<p>Dominar o pacote <code>fmt</code> em Go significa compreender três pilares fundamentais. Primeiro, os verbos de formatação e como cada um interpreta diferentes tipos de dados, desde inteiros em múltiplas bases até pontos flutuantes e unicode. Segundo, como flags, largura e precisão permitem controle fino da saída, essencial para gerar relatórios estruturados e logs legíveis. Terceiro, implementar <code>Stringer</code> e <code>Formatter</code> oferece controle total sobre como seus tipos customizados são representados, facilitando debug e tornando código mais manutenível.</p>

<p>A prática constante com estes conceitos tornará sua codificação em Go muito mais fluida. Você saberá instantaneamente qual verbo usar em cada situação e conseguirá debugar estruturas complexas com precisão. Lembre-se que <code>fmt</code> não é apenas para &quot;imprimir coisas na tela&quot; — é uma ferramenta fundamental para construir abstrações legíveis e manuteníveis.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://golang.org/pkg/fmt/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Pacote fmt</a></li>

<li><a href="https://golang.org/doc/effective_go#printing" target="_blank" rel="noopener noreferrer">Effective Go - Printing</a></li>

<li><a href="https://golang.org/pkg/fmt/" target="_blank" rel="noopener noreferrer">The Go Programming Language Specification - fmt Package</a></li>

<li><a href="https://go.dev/blog/error-handling-and-go" target="_blank" rel="noopener noreferrer">Go Blog - Error handling and Go</a></li>

<li><a href="https://www.practical-go-lessons.com/" target="_blank" rel="noopener noreferrer">Practical Go Lessons - Formatted Input/Output</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Go

Pacote net/http em Go: Servidor e Cliente HTTP da Stdlib na Prática
Pacote net/http em Go: Servidor e Cliente HTTP da Stdlib na Prática

Introdução ao Pacote net/http de Go O pacote é uma das bibliotecas padrão mai...

Select em Go: Multiplexando Channels e Timeouts: Do Básico ao Avançado
Select em Go: Multiplexando Channels e Timeouts: Do Básico ao Avançado

Introdução ao Select em Go O é uma das construções mais poderosas da linguage...

Dominando Make e New em Go: Diferenças Práticas na Alocação de Memória em Projetos Reais
Dominando Make e New em Go: Diferenças Práticas na Alocação de Memória em Projetos Reais

Make e New em Go: Diferenças Práticas na Alocação de Memória Quando você come...