Dominando os Tipos Básicos em Ruby: Números, Strings e Ranges

Embora já tenhamos nos divertido implementando programas usando arrays, hashes e procs, ainda não cobrimos os tipos mais fundamentais do Ruby: números, strings e ranges. Vamos dedicar este tutorial a esses blocos de construção essenciais que todo desenvolvedor Ruby precisa dominar.

Números em Ruby: Mais Poderosos do que Você Imagina

Ruby oferece suporte robusto para diversos tipos numéricos: inteiros, ponto flutuante, racionais e complexos. Uma das características mais impressionantes é que os inteiros podem ter qualquer comprimento, limitados apenas pela memória disponível do sistema.

Representando Números em Diferentes Bases

# Diferentes formas de representar o mesmo número
numero_decimal = 123456        # base 10
numero_decimal_explicito = 0d123456  # base 10 explícita
numero_legivel = 123_456       # underscore ignorado para legibilidade

# Outras bases numéricas
numero_hexadecimal = 0xaabb    # hexadecimal (43707)
numero_octal = 0377           # octal (255)
numero_binario = -0b10_1010   # binário negativo (-42)

# Para números muito grandes
numero_gigante = 123_456_789_123_456_789
puts numero_gigante # => 123456789123456789

Números Racionais: Precisão Matemática

Uma das funcionalidades mais elegantes do Ruby são os números racionais, que representam frações exatas:

# Cuidado: divisão normal retorna inteiro
puts 3/4          # => 0

# Diferentes formas de criar racionais
puts 3/4r         # => (3/4)
puts 0.75r        # => (3/4)
puts "3/4".to_r     # => (3/4)
puts Rational(3, 4)  # => (3/4)
puts Rational("3/4") # => (3/4)

Números Complexos: Matemática Avançada

Ruby também suporta números complexos com sintaxe literal simples:

# Diferentes formas de criar números complexos
numero_complexo = 1+2i           # => (1+2i)
numero_complexo2 = "1+2i".to_c    # => (1+2i)
numero_complexo3 = Complex(1, 2)  # => (1+2i)

# Números podem ser racionais E complexos
numero_especial = 5.7ri         # r antes do i!

Como os Números Interagem

Uma regra importante: operações entre diferentes tipos numéricos retornam o tipo mais geral:

# Regras de conversão automática
puts 1 + 2               # => 3 (inteiro)
puts 1 + 2.0             # => 3.0 (float)
puts 1.0 + 2             # => 3.0 (float)
puts 1.0 + 1+2i          # => (2.0+2i) (complexo)
puts 1 + 2/3r            # => (5/3) (racional)

# Diferentes formas de obter divisão com decimais
puts 1 / 2               # => 0 (divisão inteira)
puts 1.0 / 2             # => 0.5
puts 1.to_f / 2         # => 0.5
puts 1.fdiv(2)           # => 0.5

Iterando com Números

Os números em Ruby oferecem métodos poderosos para iteração, substituindo loops tradicionais:

# Diferentes formas de iterar
3.times { print "X " }                    # X X X
1.upto(5) { |i| print i, " " }        # 1 2 3 4 5
99.downto(95) { |i| print i, " " }   # 99 98 97 96 95
50.step(80, 5) { |i| print i, " " }  # 50 55 60 65 70 75 80

Strings: Muito Mais que Texto Simples

As strings em Ruby são sequências de caracteres extremamente versáteis. Elas podem conter texto imprimível ou dados binários, e oferecem múltiplas formas de criação e manipulação.

Literais de String e Escape Sequences

# String com aspas simples - literais
texto_simples = 'escape usando "\\"'    # => escape usando "\"
texto_aspas = 'That\'s right'          # => That's right

# String com aspas duplas - escape sequences e interpolação
texto_com_quebra = "Primeira linha\nSegunda linha"
texto_interpolado = "Segundos/dia: #{24 * 60 * 60}"  # => Segundos/dia: 86400
saudacao = "#{'Oi! ' * 3}Feliz Natal!"          # => Oi! Oi! Oi! Feliz Natal!

Delimitadores Flexíveis

Ruby oferece sintaxes alternativas para quando você precisa usar as próprias aspas dentro da string:

# %q = aspas simples, %Q = aspas duplas
string_simples = %q/string com aspas simples/
string_dupla = %Q!string com aspas duplas!
string_interpolada = %Q{Segundos/dia: #{24*60*60}}

# % sozinho = aspas duplas
string_default = %!string com aspas duplas!
string_parenteses = %(Segundos/dia: #{24*60*60})

Here Documents (Heredoc)

Para strings multi-linha, Ruby oferece a sintaxe heredoc:

def string_longa
  <<~FIM_DA_STRING
    Mais rápido que uma bala, mais poderoso que
    uma locomotiva, capaz de pular prédios altos
    num único salto—olhe, lá no céu, é um pássaro,
    é um avião, é o Superman!
  FIM_DA_STRING
end

puts string_longa

Exemplo Prático: Processando Dados de Playlist

Vamos ver um exemplo prático de manipulação de strings processando um arquivo de playlist musical:

# Estrutura para armazenar dados da música
Musica = Struct.new(:titulo, :artista, :duracao)

# Exemplo de linha do arquivo:
# /jazz/j00132.mp3 | 3:45 | Fats Waller | Ain't Misbehavin'

linha_exemplo = "/jazz/j00132.mp3 | 3:45 | Fats  Waller | Ain't Misbehavin'"

# Separar campos usando regex
_arquivo, duracao, artista, titulo = linha_exemplo.split(/\s*\|\s*/)

# Remover espaços extras do nome do artista
artista_limpo = artista.squeeze(" ")    # "Fats  Waller" -> "Fats Waller"

# Converter duração de mm:ss para segundos
minutos, segundos = duracao.scan(/\d+/)     # ["3", "45"]
duracao_segundos = minutos.to_i * 60 + segundos.to_i

# Criar objeto da música
musica = Musica.new(titulo, artista_limpo, duracao_segundos)
puts musica
# => #

Ranges: Sequências e Intervalos Elegantes

Os ranges em Ruby representam sequências de valores com início, fim e forma de gerar valores sucessivos. Eles são fundamentais para expressar intervalos de forma natural e eficiente.

Ranges como Sequências

# Range inclusivo (dois pontos)
numeros_inclusivo = 1..10              # inclui 1 e 10
letras = "a".."z"                     # todas as letras

# Range exclusivo (três pontos)
numeros_exclusivo = 0...3             # inclui 0, 1, 2 (exclui 3)

# Converter para array
puts (1..10).to_a             # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
puts ('bar'..'bat').to_a          # => ["bar", "bas", "bat"]

# Ranges infinitos
array_exemplo = [1, 2, 3, 4, 5, 6]
puts array_exemplo[..2]           # => [1, 2, 3] (do início até índice 2)
puts array_exemplo[2..]           # => [3, 4, 5, 6] (do índice 2 até o fim)

Métodos Úteis com Ranges

digitos = 0..9

# Testando inclusão
puts digitos.include?(5)           # => true

# Valor máximo
puts digitos.max                   # => 9

# Rejeitar valores menores que 5
puts digitos.reject { |i| i < 5 }   # => [5, 6, 7, 8, 9]

# Somar todos os valores
puts digitos.reduce(:+)           # => 45

Ranges como Intervalos

Uma aplicação poderosa dos ranges é como testes de intervalo, especialmente em declarações case:

# Testando se um valor está em um intervalo
puts (1..10) === 5          # => true
puts (1..10) === 15         # => false
puts (1..10) === 3.14159    # => true

# Aplicação prática: classificando idade de carros
idade_carro = 9.5

case idade_carro
when 0...1
  puts "Mmm.. cheiro de carro novo"
when 1...3
  puts "Novo e bonito"
when 3...10
  puts "Confiável mas com alguns arranhões"
when 10...30
  puts "Carro velho"
else
  puts "Relíquia vintage"
end
# => Confiável mas com alguns arranhões

Diferença entre include? e cover?

É importante entender a diferença entre estes dois métodos ao trabalhar com ranges:

range_letras = 'a'..'j'

# include? verifica se o valor está na sequência
puts range_letras.include?('c')     # => true
puts range_letras.include?('bb')    # => false (não existe na sequência)

# cover? verifica se está entre início e fim
puts range_letras.cover?('bb')      # => true (está entre 'a' e 'j')

Armadilha Comum: Strings Numéricas

Uma pegadinha importante para desenvolvedores vindos de outras linguagens: strings que contêm apenas dígitos não são automaticamente convertidas em números:

# PROBLEMA: Tentando somar números de um arquivo
dados_exemplo = ["3 4", "5 6", "7 8"]

dados_exemplo.each do |linha|
  v1, v2 = linha.split  # dividir linha em espaços
  print v1 + v2, " "        # ERRO: concatena strings!
end
# Saída: 34 56 78 (concatenação, não soma!)

# SOLUÇÃO: Converter explicitamente para inteiros
dados_exemplo.each do |linha|
  v1, v2 = linha.split
  print Integer(v1) + Integer(v2), " "
end
# Saída: 7 11 15 (soma correta!)

Conclusão

Dominar os tipos básicos do Ruby - números, strings e ranges - é fundamental para escrever código Ruby idiomático e eficiente. Estes tipos oferecem funcionalidades ricas que vão muito além do que encontramos em linguagens mais simples. Os números suportam diferentes bases e tipos matemáticos avançados, as strings oferecem múltiplas sintaxes e manipulação poderosa, e os ranges proporcionam uma forma elegante de expressar sequências e intervalos.

Lembre-se sempre de converter strings para números quando necessário, aproveite a flexibilidade dos diferentes delimitadores de string, e use ranges para tornar seu código mais expressivo e legível. Esses conceitos serão a base sólida para tudo que construirmos daqui em diante no Ruby.

Comentários (0)

Nenhum comentário:

Postar um comentário