O tipo rune em Go é um alias para int32.
Dado esse tipo int32 subjacente, o tipo rune armazena um valor inteiro de 32 bits com sinal.
No entanto, diferentemente 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. 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 mostra exemplos de caracteres Unicode junto com seus pontos de código Unicode 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, já que um tipo int32 é capaz de armazenar até 4 bytes de dados.
Os arquivos de código-fonte em Go são codificados usando 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 produzirá int32:
myRune := '¿'
fmt.Printf("myRune type: %T\n", myRune)
// Output: myRune type: int32
Da mesma forma, imprimir o valor de uma rune produzirá 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
As strings em Go são codificadas usando UTF-8, o que significa que elas contêm caracteres Unicode. Os caracteres em uma string são armazenados e codificados como 1, 2, 3 ou 4 bytes, dependendo do caractere Unicode que representam.
Em Go, slices são usados para representar sequências, e podemos iterar sobre eles usando 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!)
Ainda que uma string seja apenas um slice de bytes, a palavra-chave range itera sobre as runes de uma string, não sobre 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 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 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
Você recebeu a tarefa de criar uma biblioteca de log para ajudar a gerenciar os logs da sua organização. Esta biblioteca permitirá identificar qual aplicação emitiu um determinado log, corrigir logs corrompidos e determinar se uma linha de log está dentro de um certo limite de caracteres.
Os logs vêm de várias aplicações, e cada uma usa o seu próprio formato de log proprietário. É preciso identificar a aplicação que emitiu um log antes de armazená-lo em um sistema de agregação de logs.
Implemente a função Application, que recebe uma linha de log e retorna a aplicação que emitiu essa linha de log.
Para identificar qual aplicação emitiu uma determinada linha de log, procure na linha de log por um caractere específico, conforme a tabela a seguir:
| Aplicação | Caractere | Ponto de código Unicode |
|---|---|---|
recommendation |
❗ | U+2757 |
search |
🔍 | U+1F50D |
weather |
☀ | U+2600 |
Se uma linha de log não contiver nenhum dos caracteres da tabela acima, retorne default para quem chamou a função.
Se uma linha de log contiver mais de um caractere da tabela acima, retorne a aplicação correspondente ao primeiro caractere encontrado na linha, da esquerda para a direita.
Application("❗ recommended search product 🔍")
// => recommendation
Por causa de um bug raro, mas persistente, na infraestrutura de log, certos caracteres nos logs podem acabar corrompidos. Depois de passar um tempo identificando os caracteres corrompidos e o valor original deles, você decide atualizar a biblioteca de log para ajudar a corrigir logs corrompidos.
Implemente a função Replace, que recebe uma linha de log, um caractere corrompido e o valor original, e retorna uma linha de log modificada, com todas as ocorrências do caractere corrompido substituídas pelo valor original.
log := "please replace '👎' with '👍'"
Replace(log, '👎', '👍')
// => please replace '👍' with '👍'"
Os sistemas responsáveis por exibir logs têm um limite para o número de caracteres que podem ser exibidos por linha de log. Por isso, as pessoas estão pedindo que esta biblioteca inclua uma função auxiliar para determinar se uma linha de log está dentro de um limite específico de caracteres.
Implemente a função WithinLimit, que recebe uma linha de log e um limite de caracteres e retorna se a linha de log está ou não dentro do limite de caracteres.
WithinLimit("hello❗", 6)
// => true
Crie sua conta no Exercism para aprender e dominar Go com 34 conceitos165 exercícios e mentoria humana de verdade, tudo de graça.