Ru

Runes em Go

3 exercícios

Sobre Runes

O tipo rune em Go é um alias de int32. Dado este tipo int32 subjacente, o tipo rune contém um valor inteiro com sinal de 32 bits. No entanto, ao contrário do tipo int32, o valor inteiro guardado num tipo rune representa um único caráter Unicode.

Unicode e pontos de código Unicode

O Unicode é um superconjunto do ASCII que representa carateres atribuindo um número único a cada caráter. Este número único chama-se ponto de código Unicode. O Unicode tem como objetivo representar todos os carateres do mundo, incluindo vários alfabetos, números, símbolos e até emoji, como pontos de código Unicode.

Em Go, o tipo rune representa um único ponto de código Unicode.

A tabela seguinte contém exemplos de carateres Unicode, juntamente com o respetivo ponto de código Unicode e valor decimal:

Caráter 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

UTF-8 é uma codificação de carateres de largura variável que é 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 no máximo em 4 bytes, o tipo rune tem de conseguir conter até 4 bytes de dados. É por isso que o tipo rune é um alias de int32, já que um tipo int32 é capaz de conter até 4 bytes de dados.

Os ficheiros de código-fonte Go são codificados em UTF-8.

Como usar runes

As variáveis do tipo rune são declaradas colocando um caráter entre aspas simples:

myRune := '¿'

Como rune é apenas um alias de int32, imprimir o tipo de uma rune devolve int32:

myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32

Do mesmo modo, imprimir o valor de uma rune devolve o seu valor inteiro (decimal):

myRune := '¿'
fmt.Printf("myRune value: %v\n", myRune)
// Output: myRune value: 191

Para imprimir o caráter Unicode representado pela rune, usa 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, usa 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 definires uma rune envolvendo o caráter em aspas simples, também podes especificar o número hexadecimal ou decimal:

myRune := rune(0xbf)
myRune = 191
fmt.Printf("myRune Unicode character: %c\n", myRune)
// Output: myRune Unicode character: ¿

Runes e strings

As strings em Go são codificadas em UTF-8, o que significa que contêm carateres Unicode. Os carateres dentro das strings são guardados e codificados em 1, 2, 3 ou 4 bytes, dependendo do caráter Unicode que representam.

Em Go, usam-se slices para representar sequências, e essas slices podem ser percorridas com range. Quando iteramos sobre uma string, o Go converte-a numa série de runes, cada uma com 4 bytes (lembra-te: o tipo rune é um alias de int32!)

Apesar de uma string ser apenas uma slice de bytes, a palavra-chave range itera sobre as runes de uma string, e não sobre os seus bytes.

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 guardadas em 1, 2, 3 ou 4 bytes, o comprimento de uma string pode não ser sempre igual ao número de carateres dessa string. Usa a função incorporada len para obteres o comprimento de uma string em bytes e a função utf8.RuneCountInString para obteres o número de runes de 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

Conversão de tipo de runes

Uma slice de runes pode ser convertida para uma string:

myRuneSlice := []rune{'e', 'x', 'e', 'r', 'c', 'i', 's', 'm'}
myString := string(myRuneSlice)
fmt.Println(myString)
// Output: exercism

Do mesmo modo, uma string pode ser convertida para uma slice de runes. Lembra-te: sem verbos de formatação, imprimir uma rune devolve o seu valor inteiro (decimal):

myString := "exercism"
myRuneSlice := []rune(myString)
fmt.Println(myRuneSlice)
// Output: [101 120 101 114 99 105 115 109]
Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Runes

A prática está bloqueada

Desbloqueia mais 2 exercícios para praticares Runes