Basicamente, existem dois tipos de laços:
As duas formas são possíveis em Julia, embora a segunda possa ser mais comum.
while
Para problemas em aberto, em que não se sabe de antemão quantas vezes o laço vai repetir, Julia tem o laço while.
A forma básica é bem simples:
while condition
do_something()
end
Nesse caso, o programa continua repetindo o laço até que condition deixe de ser true.
Há duas formas de sair do laço antes do fim:
break faz o laço terminar, e a execução continua na linha seguinte ao end do laço.return x interrompe a execução da função atual, devolvendo o valor de retorno x a quem fez a chamada.Com essas opções disponíveis, às vezes é conveniente criar um laço "infinito" com while true ... end e então contar com a descoberta de uma condição de parada dentro do corpo do laço para disparar um break ou um return.
A ilustração mais simples é percorrer um intervalo.
Se quisermos fazer algo 10 vezes:
for n in 1:10
do_something(n)
end
Se a iteração atual não satisfizer alguma condição, é possível pular imediatamente para a próxima iteração com um continue:
for n in 1:10
if is_useless(n)
continue
end
# we decided this iteration could be useful
do_something_slow(n)
end
Em uma forma mais curta, o bloco if poderia ser substituído por is_useless(n) && continue.
Muitos outros tipos de coleção podem ser percorridos: elementos de um array, caracteres de uma string, chaves de um dicionário...
O requisito é que a coleção seja iterable.
Isso será explicado com mais detalhes em um conceito posterior, mas, em essência, a coleção precisa ter uma forma de fornecer o próximo item quando solicitada, além de uma forma de indicar que o fim foi alcançado e não há mais itens.
Os exemplos até aqui percorrem o intervalo 1:10, em que o valor também é o índice do laço.
De modo mais geral, pode ser que o índice seja necessário, e não apenas o valor.
Para isso, usa-se a função eachindex(), por exemplo for i in eachindex(my_array) ... end.
Escrever laços explícitos tende a ser menos comum em Julia do que em muitas linguagens tradicionais, porque há várias opções mais concisas.
Uma situação especialmente comum é quando precisamos construir um novo vetor a partir dos elementos de alguma outra coleção (vetor, string, conjunto... há muitas possibilidades).
Quem gosta de compreensões de lista em Python vai ficar contente em saber que Julia pode usar sintaxe semelhante.
A essência disso é montar um laço bem compacto dentro de um vetor.
A sintaxe mais simples tem a forma result = [f(x) for x in some_collection].
Com um laço tradicional, isso poderia ser escrito assim:
result = []
for x in some_collection
push!(result, f(x))
end
Opcionalmente, pode-se adicionar uma condicional no final, para selecionar apenas os elementos da coleção que correspondem:
# multiples of 3
julia> [n^2 for n in 1:10 if n%3 == 0]
3-element Vector{Int64}:
9
36
81
# letters beyond 'h' in the alphabet
julia> [uppercase(c) for c in "Julia" if c > 'h']
3-element Vector{Char}:
'U': ASCII/Unicode U+0055 (category Lu: Letter, uppercase)
'L': ASCII/Unicode U+004C (category Lu: Letter, uppercase)
'I': ASCII/Unicode U+0049 (category Lu: Letter, uppercase)
A sintaxe é semelhante à do Python, mas não idêntica. Há algumas diferenças para múltiplas variáveis e/ou arrays multidimensionais, então esse assunto será abordado com mais detalhes em um conceito posterior.
Como uma linguagem moderna e majoritariamente funcional, Julia (claro) tem várias formas de operar sobre coleções, não apenas um laço explícito ou um laço compactado em uma compreensão.
Conceitos posteriores vão abordar alternativas como broadcasting e funções de ordem superior.