Neste documento, apresentamos a sintaxe básica da linguagem Julia. Nosso objetivo é mostrar que essa linguagem é leve e fácil de usar.
Vamos apresentar
x = 2.6
y = -7.5
x + y
-4.9
z = sqrt(x^2 + y^2);
z
7.937883848986454
a = 1
b = 0
a == b
false
string1 = "Quantas vezes "
"Quantas vezes "
string2 = "você leu a apostila?"
"você leu a apostila?"
string(string1, string2)
"Quantas vezes você leu a apostila?"
x = 2
println("Não me lembro bem, mas pelo menos umas $x vezes.")
Não me lembro bem, mas pelo menos umas 2 vezes.
Podemos criar uma upla especificando uma sequência ordenada de elementos entre parêntesis ()
.
(item1, item2, ...)
frutas = ("melão", "abacaxi", "manga")
("melão", "abacaxi", "manga")
frutas[1]
"melão"
p = (5, -3)
(5, -3)
p[2]
-3
Se temos conjuntos de dados relacionados um ao outro, podemos armazená-los em um dicionário.
Para fazer isso, usamos a função Dict()
.
Dict(chave1 => valor1, chave2 => valor2, ...)
Um bom exemplo de dicionário é uma lista de contatos, onde associamos telefones a nomes.
agenda_de_telefones = Dict("João" => "99999-0000", "Maria" => "11111-2222")
Dict{String, String} with 2 entries: "Maria" => "11111-2222" "João" => "99999-0000"
agenda_de_telefones["Maria"]
"11111-2222"
Diferentemente de uplas, listas podem ser modificadas.
Diferentemente de dicionários, listas contêm sequências ordenadas de elementos.
Podemos criar uma lista especificando uma sequência entre colchetes []
.
[item1, item2, ...]
Por exemplo, podemos criar uma lista com uma sequência de tarefas a fazer.
tarefas = ["caminhar", "estudar", "comer", "dormir"]
4-element Vector{String}: "caminhar" "estudar" "comer" "dormir"
fibonacci = [1, 1, 2, 3, 5, 8, 13]
7-element Vector{Int64}: 1 1 2 3 5 8 13
lista_mista = [1, 3, 7, "verde", "azul"]
5-element Vector{Any}: 1 3 7 "verde" "azul"
Podemos também criar listas de outras estruturas de dados ou listas multidimensionais.
números = [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
3-element Vector{Vector{Int64}}: [1, 2] [3, 4, 5] [6, 7, 8, 9]
M = rand(4, 3)
4×3 Matrix{Float64}: 0.935469 0.946714 0.874511 0.498354 0.553129 0.798912 0.820358 0.415443 0.0983551 0.62491 0.778879 0.53726
Acima, o comando rand(4, 3)
cria uma lista de quatro linhas e três colunas com números aleatórios.
for
¶A sintaxe para um laço do tipo for
é
for *variável* in *loop iterable*
*comandos*
end
for n in 1:10
println(n)
end
1 2 3 4 5 6 7 8 9 10
n = 0
while n < 10
n += 1
println(n)
end
1 2 3 4 5 6 7 8 9 10
if
¶Em Julia, a sintaxe
if *condição 1*
*opção 1*
elseif *condição 2*
*opção 2*
else
*opção 3*
end
permite executar, condicionalmente, uma das opções.
x = 7
y = 3
if x > y
x
else
y
end
7
O operador ternário a seguir nos fornece uma alternativa para representar uma condicional do tipo if
.
A sintaxe
a ? b : c
significa o mesmo que
if a
b
else
c
end
Portanto, podemos reescrever o código da célula anterior da seguinte forma:
x = 7
y = 3
(x > y) ? x : y
7
Tópicos:
function
e end
¶function f(x)
x^2
end
f (generic function with 1 method)
f(3)
9
=
¶g(x) = x^2
g (generic function with 1 method)
g(-2)
4
h = x -> x^2
#1 (generic function with 1 method)
h(9)
81
"If it quacks like a duck, it's a duck."
Duck-typing em Julia significa que as funções em Julia vão funcionar com qualquer argumento que faça sentido.
Por exemplo, f(x)=x^2
vai funcionar se o argumento for uma matriz quadrada, pois faz sentido multiplicar uma matriz quadrada por ela mesma.
A = rand(3, 3)
3×3 Matrix{Float64}: 0.258506 0.503305 0.865922 0.241912 0.420527 0.748512 0.688515 0.910238 0.0577069
f(A)
3×3 Matrix{Float64}: 0.784782 1.12996 0.650546 0.679628 0.979923 0.567441 0.437915 0.78184 1.28085
Todavia, se o argumento passado a f
for um vetor, ocorrerá um erro pois não é claro o que significa multiplicar um vetor por ele mesmo.
v = rand(3)
3-element Vector{Float64}: 0.5052215340330571 0.45450555631789546 0.9695914133033307
f(v)
MethodError: no method matching ^(::Vector{Float64}, ::Int64) Closest candidates are: ^(::Union{AbstractChar, AbstractString}, ::Integer) at strings/basic.jl:730 ^(::Complex{<:AbstractFloat}, ::Integer) at complex.jl:860 ^(::Complex{<:Integer}, ::Integer) at complex.jl:862 ... Stacktrace: [1] literal_pow @ ./intfuncs.jl:340 [inlined] [2] f(x::Vector{Float64}) @ Main ./In[24]:2 [3] top-level scope @ In[33]:1 [4] eval @ ./boot.jl:368 [inlined] [5] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1428
Por convenção, funções seguidas de !
alteram seus conteúdos e funções não seguidas de !
não alteram.
Por exemplo, vamos ver a diferença entre sort
e sort!
.
v = [5, 9, 1]
3-element Vector{Int64}: 5 9 1
sort(v)
3-element Vector{Int64}: 1 5 9
v
3-element Vector{Int64}: 5 9 1
O comando sort(v)
retorna uma lista que contém os elementos de v
em ordem crescente, mas a lista v
não é alterada.
Por outro lado, quando executamos sort!(v)
, a lista v
é alterada e colocada em ordem crescente.
sort!(v)
3-element Vector{Int64}: 1 5 9
v
3-element Vector{Int64}: 1 5 9
map
¶A função map
é uma função de ordem superior em Julia que recebe uma função como argumento.
A função map
então aplica a função em cada elemento de uma estrutura de dados que também é passada como argumento.
Por exemplo, o comando
map(f, [1, 2, 3])
fornece uma lista cujos elementos são obtidos aplicando f
a cada elemento de [1, 2, 3]
:
[f(1), f(2), f(3)]
map(f, [1, 2, 3])
3-element Vector{Int64}: 1 4 9
Também é possível passar para a função map
uma função anônima:
map(x -> x^3, [1, 2, 3])
3-element Vector{Int64}: 1 8 27
broadcast
¶A função broadcast
é outra função de order superior em Julia.
A função broadcast
é uma generalização da função map
, ou seja, pode fazer tudo que a função map
faz, e mais.
A sintaxe usada para executar broadcast
é semelhante à usada para executar map
.
broadcast(f, [1, 2, 3])
3-element Vector{Int64}: 1 4 9
Novamente, aplicamos f
a todos os elementos de [1, 2, 3]
, desta vez usando broadcast
.
Uma forma equivalente de executar broadcast
é inserir um .
entre o nome da função que você quer aplicar e os argumentos de entrada.
Por exemplo,
broadcast(f, [1, 2, 3])
é equivalente a
f.([1, 2, 3])
f.([1, 2, 3])
3-element Vector{Int64}: 1 4 9
Observe a diferença entre executar o comando acima e executar o comando
f([1, 2, 3])
Nós podemos elevar cada elemento de um vetor ao quadrado, mas não podemos elevar o vetor ao quadrado.
Mais uma vez, observamos a diferença entre
f(A)
e
f.(A)
para uma matrix A
.
A = [i + 3j for j in 0:2, i in 1:3]
3×3 Matrix{Int64}: 1 2 3 4 5 6 7 8 9
f(A)
3×3 Matrix{Int64}: 30 36 42 66 81 96 102 126 150
Novamente, vemos que
f(A) = A^2 = A*A
enquanto as entradas de
f.(A)
são os quadrados das entradas de A
:
f.(A)
3×3 Matrix{Int64}: 1 4 9 16 25 36 49 64 81
A sintaxe usando .
permite expressar operações pontuais com uma notação elegante do ponto de vista matemático.
Por exemplo, podemos escrever
B = A .+ 2 .* f.(A) ./ A
3×3 Matrix{Float64}: 3.0 6.0 9.0 12.0 15.0 18.0 21.0 24.0 27.0
em vez de
B = broadcast(x -> x + 2*f(x) / x, A)
3×3 Matrix{Float64}: 3.0 6.0 9.0 12.0 15.0 18.0 21.0 24.0 27.0