O tipo rune em Go é um alias para int32.
Dado esse tipo subjacente int32, o tipo rune armazena um valor inteiro de 32 bits com sinal.
No entanto, ao contrário de um tipo int32, o valor inteiro armazenado em um tipo rune representa um único caractere Unicode.
Unicode é um superconjunto do ASCII que representa caracteres atribuindo um número único a cada caractere. Esse número único é chamado de ponto de código Unicode. O Unicode tem como objetivo representar todos os caracteres do mundo, incluindo diversos alfabetos, números, símbolos e até emojis, como pontos de código Unicode.
Em Go, o tipo rune representa um único ponto de código Unicode.
A tabela a seguir contém exemplos de caracteres Unicode com seus pontos de código e valores decimais:
| Caractere Unicode | Ponto de código Unicode | Valor decimal |
|---|---|---|
| 0 | U+0030 |
48 |
| A | U+0041 |
65 |
| a | U+0061 |
97 |
| ¿ | U+00BF |
191 |
| π | U+03C0 |
960 |
| 🧠 | U+1F9E0 |
129504 |
UTF-8 é uma codificação de caracteres de largura variável usada para codificar cada ponto de código Unicode em 1, 2, 3 ou 4 bytes.
Como um ponto de código Unicode pode ser codificado em no máximo 4 bytes, o tipo rune precisa ser capaz de armazenar até 4 bytes de dados.
É por isso que o tipo rune é um alias para int32: o tipo int32 é capaz de armazenar até 4 bytes de dados.
Os arquivos de código-fonte Go são codificados em UTF-8.
Variáveis do tipo rune são declaradas colocando um caractere entre aspas simples:
myRune := '¿'
Como rune é apenas um alias para int32, imprimir o tipo de uma rune produz int32:
myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32
Da mesma forma, imprimir o valor de uma rune produz seu valor inteiro (decimal):
myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191
Para imprimir o caractere Unicode representado pela rune, use o verbo de formatação %c:
myRune := '¿'
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
Para imprimir o ponto de código Unicode representado pela rune, use o verbo de formatação %U:
myRune := '¿'
fmt.Printf("myRune Unicode code point: %U\n", myRune)
// Output: myRune Unicode code point: U+00BF
Além de definir uma rune colocando o caractere entre aspas simples, você também pode especificar o número hexadecimal ou decimal:
myRune := rune(0xbf)
myRune = 191
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿
As strings em Go são codificadas em UTF-8, o que significa que elas contêm caracteres Unicode. Os caracteres em strings são armazenados e codificados como 1, 2, 3 ou 4 bytes, dependendo do caractere Unicode que representam.
Em Go, usamos slices para representar sequências, e podemos iterar sobre eles com range.
Quando iteramos sobre uma string, Go converte a string em uma série de runes, cada uma com 4 bytes (lembre-se, o tipo rune é um alias para um int32!)
Mesmo que uma string seja apenas um slice de bytes, a palavra-chave range itera sobre as runes de uma string, e não sobre os bytes dela.
Neste exemplo, a variável index representa o índice inicial da sequência de bytes da rune atual e a variável char representa a rune atual:
myString := "❗hello"
for index, char := range myString {
fmt.Printf("Index: %d\tCharacter: %c\t\tCode Point: %U\n", index, char, char)
}
// Output:
// Index: 0 Character: ❗ Code Point: U+2757
// Index: 3 Character: h Code Point: U+0068
// Index: 4 Character: e Code Point: U+0065
// Index: 5 Character: l Code Point: U+006C
// Index: 6 Character: l Code Point: U+006C
// Index: 7 Character: o Code Point: U+006F
Como as runes podem ser armazenadas em 1, 2, 3 ou 4 bytes, o comprimento de uma string nem sempre é igual ao número de caracteres dela.
Use a função embutida len para obter o comprimento de uma string em bytes e a função utf8.RuneCountInString para obter o número de runes em uma string:
import "unicode/utf8"
myString := "❗hello"
stringLength := len(myString)
numberOfRunes := utf8.RuneCountInString(myString)
fmt.Printf("myString - Length: %d - Runes: %d\n", stringLength, numberOfRunes)
// Output: myString - Length: 8 - Runes: 6
Um slice de runes pode ser convertido para string com uma conversão de tipo:
myRuneSlice := []rune{'e', 'x', 'e', 'r', 'c', 'i', 's', 'm'}
myString := string(myRuneSlice)
fmt.Println(myString)
// Output: exercism
Da mesma forma, uma string pode ser convertida para um slice de runes com uma conversão de tipo. Lembre-se: sem verbos de formatação, imprimir uma rune produz seu valor inteiro (decimal):
myString := "exercism"
myRuneSlice := []rune(myString)
fmt.Println(myRuneSlice)
// Output: [101 120 101 114 99 105 115 109]