Tipos de Caracteres em Golang

GolangBeginner
Pratique Agora

Introdução

Na seção anterior, discutimos os tipos numéricos mais utilizados. Nesta etapa, vamos aprender sobre os tipos de caracteres na linguagem Go.

Conteúdos Abordados:

  • Codificação ASCII
  • Codificação UTF-8
  • Conjunto de Caracteres Unicode
  • byte
  • rune

Codificação ASCII

Nos primórdios da computação, utilizava-se o formato de codificação ASCII (American Standard Code for Information Interchange). Ele representava caracteres usando 7 bits, o que permitia um total de 128 (2^7) combinações. Os caracteres do bit 0 ao 31, além do bit 127, representavam caracteres de controle não exibíveis, enquanto os caracteres do bit 32 ao 126 representavam letras maiúsculas e minúsculas do cotidiano, números e sinais de pontuação. Consulte a tabela para mais detalhes.

Com a evolução dos computadores, surgiu a necessidade de suportar diferentes idiomas. A codificação ASCII mostrou-se insuficiente para esse propósito. Consequentemente, diversos idiomas desenvolveram seus próprios formatos de codificação, como o GB2312 para chinês simplificado, EUC-KR para coreano e KOI8-R para russo.

No entanto, com a enorme variedade de famílias linguísticas no mundo, tornou-se necessário um formato de codificação único que pudesse unificar todos os idiomas. O Unicode foi criado justamente para suprir essa necessidade.

Conjunto de Caracteres Unicode

Em 1991, o Unicode Consortium lançou a primeira versão do conjunto de caracteres Unicode. Seu objetivo era unificar todos os idiomas em um único formato de codificação, permitindo que computadores em todo o mundo exibissem e processassem textos com mais facilidade, evitando problemas de compatibilidade em ambientes multilíngues.

Contudo, o Unicode era apenas um conjunto de caracteres; ele definia os códigos dos caracteres, mas não como eles deveriam ser armazenados fisicamente. Isso dificultou sua adoção em larga escala por muito tempo, até a ascensão da Internet.

Codificação UTF-8

Com o desenvolvimento contínuo da Internet, o UTF-8, uma implementação de codificação Unicode, ganhou popularidade. Trata-se de uma codificação de comprimento variável, o que significa que diferentes símbolos podem ter diferentes tamanhos de bytes no UTF-8.

Por exemplo, letras do alfabeto inglês, que estão dentro da faixa ASCII, são representadas por 1 byte. O caractere 'y' (valor Unicode 121) ocupa 1 byte.

Para o uso cotidiano, a maioria dos caracteres chineses ocupa 3 bytes. Por exemplo, o caractere '实' (valor Unicode 23454) ocupa 3 bytes.

No entanto, existem alguns caracteres chineses que ocupam 4 bytes. Isso ocorre porque existem mais de 100.000 caracteres chineses, mas, conforme a estrutura técnica, 3 bytes só podem representar pouco mais de 60.000 caracteres, exigindo que uma pequena parcela utilize 4 bytes.

Outra vantagem da codificação UTF-8 é a sua compatibilidade retroativa com o ASCII. Na verdade, o ASCII é um subconjunto do UTF-8. Os primeiros 128 caracteres no UTF-8 correspondem um para um aos caracteres ASCII. Isso significa que softwares que originalmente usavam ASCII podem continuar sendo utilizados com pouca ou nenhuma modificação. Devido a essas vantagens, o UTF-8 tornou-se gradualmente o formato de codificação preferido mundialmente.

Os criadores da linguagem de programação Go, Rob Pike e Ken Thompson, também foram os inventores do UTF-8, por isso o Go possui uma afinidade especial com este formato. O Go exige que os arquivos de código-fonte sejam salvos em codificação UTF-8. Ao manipular caracteres de texto, o UTF-8 é a escolha padrão. Além disso, a biblioteca padrão oferece diversas funções relacionadas à codificação e decodificação UTF-8.

byte e rune

O tipo byte é um apelido (alias) para uint8 e ocupa um byte (8 bits). Ele pode ser usado para representar todos os caracteres da tabela ASCII. No entanto, como o byte possui uma faixa limitada de valores (256 ou 2^8), ao lidar com caracteres compostos, como os caracteres chineses ou símbolos complexos, precisamos utilizar o tipo rune.

Crie um novo arquivo chamado byte.go e insira o seguinte código:

cd ~/project
touch byte.go
package main

import "fmt"

func main() {
    var a byte = 76
    fmt.Printf("Value of a: %c\n", a)

    var b uint8 = 76
    fmt.Printf("Value of b: %c\n", b)

    var c byte = 'L'
    fmt.Printf("Value of c: %c\n", c)
}

Após executar o programa, o seguinte resultado será exibido:

go run byte.go
Value of a: L
Value of b: L
Value of c: L

O marcador %c é utilizado para exibir caracteres. É possível notar que o tipo byte e o tipo uint8 produzem a mesma saída quando possuem o mesmo valor. Consultando a tabela ASCII, vemos que o valor ASCII da letra 'A' é 65. Quando usamos o marcador de número inteiro %d para exibir o valor, ele também resulta em 65.

Portanto, fica evidente que o byte no Go é equivalente ao uint8 dos tipos inteiros. O mesmo princípio se aplica ao rune, mas ele representa uma faixa diferente de valores inteiros.

O tipo rune é um apelido para int32 e ocupa quatro bytes (32 bits). Ele é utilizado para representar caracteres compostos, como emojis.

Atualize o arquivo byte.go com o seguinte código:

package main

import "fmt"

func main() {
    var a rune = '😊' // Emoji de sorriso
    fmt.Printf("Value of a: %c\n", a)

    var b int32 = 9829 // Representação decimal de um caractere Unicode (Símbolo de coração)
    fmt.Printf("Value of b: %c\n", b)
    var c rune = 0x1F496 // Representação hexadecimal de um caractere Unicode (Emoji de coração brilhante)
    fmt.Printf("Value of c: %c\n", c)

    var d rune = '\u0041' // Caractere Unicode representado pelo seu code point (Letra maiúscula 'A')
    fmt.Printf("Value of d: %c\n", d)
    var e rune = '\U0001F609' // Caractere Unicode representado pelo seu code point (Emoji de rosto piscando)
    fmt.Printf("Value of e: %c\n", e)
}

Após executar o programa, a seguinte saída será exibida:

go run byte.go

Nota: Execute o programa no Terminal do Desktop ou do WebIDE, mas evite executá-lo na aba Terminal localizada no topo da VM do LabEx.

Value of a: 😊
Value of b: ♥
Value of c: 💖
Value of d: A
Value of e: 😉
  • A variável a representa o emoji de sorriso '😊'.
  • A variável b é inicializada com a representação decimal de um caractere Unicode (9829), que corresponde ao símbolo de coração '♥'.
  • A variável c é inicializada com a representação hexadecimal de um caractere Unicode (0x1F496), que corresponde ao emoji de coração brilhante '💖'.
  • A variável d representa a letra maiúscula 'A' usando o formato Unicode \u0041.
  • A variável e representa o emoji de rosto piscando '😉' usando o formato \U com o code point 0001F609.

Nota: Em Go, aspas simples e aspas duplas não são a mesma coisa. Aspas simples são usadas para representar caracteres individuais, enquanto aspas duplas são usadas para declarar strings (cadeias de caracteres). Portanto, deve-se usar aspas simples ao declarar tipos byte e rune, caso contrário, ocorrerá um erro.

Desafio

Agora, vamos reforçar o que aprendemos. Crie um novo arquivo chamado rune.go e insira o código abaixo. Complete o código de modo que o número hexadecimal 0x1F648 seja atribuído à variável a e o programa exiba seu valor corretamente.

  • Requisitos: O arquivo rune.go deve ser colocado no diretório ~/project.
  • Dica: Para números hexadecimais longos, deve-se utilizar um formato específico.
package main

import "fmt"

func main() {
    var a rune = 0x1F648
    fmt.Printf("The value of a is: %c\n", a)
}
✨ Verificar Solução e Praticar

Resumo

Vamos recapitular o que aprendemos nesta seção:

  • Caracteres ASCII ocupam um byte e podem representar 128 caracteres diferentes.
  • A codificação UTF-8 é uma forma de implementar o conjunto de caracteres Unicode. É uma codificação de comprimento variável, e seu tamanho em bytes varia dependendo do caractere representado.
  • O tipo de dado byte pode ser usado para representar caracteres ASCII, enquanto o tipo de dado rune é utilizado para representar caracteres Unicode.
  • O tipo byte é essencialmente um apelido para inteiros de 8 bits, e o rune para inteiros de 32 bits.

Nesta seção, explicamos primeiro os conceitos de ASCII, UTF-8 e Unicode. Em seguida, detalhamos a relação entre os tipos de caracteres byte e rune com os tipos de dados inteiros.