Una Tuple es bastante similar a un Vector (un array unidimensional) en muchos aspectos.
Sin embargo, hay algunas diferencias importantes.
( ) en lugar de corchetes [ ], aunque los paréntesis se pueden omitir cuando el significado no es ambiguo.La inmutabilidad permite más optimizaciones del compilador y hace que las tuplas tengan mejor rendimiento que los vectores, así que conviene preferirlas cuando la mutabilidad no sea necesaria.
julia> t = (3, 5.2, "xyz")
(3, 5.2, "xyz")
# Non-homogeneous:
julia> dump(t)
Tuple{Int64, Float64, String}
1: Int64 3
2: Float64 5.2
3: String "xyz"
julia> t[2]
5.2
# Immutable:
julia> t[2] = 7.3
ERROR: MethodError: no method matching setindex!(::Tuple{Int64, Float64, String}
También existe un constructor Tuple(), que convierte cualquier colección iterable en una tupla.
De forma muy útil, esto trata un string como una colección iterable de caracteres.
julia> Tuple("Julia")
('J', 'u', 'l', 'i', 'a')
En cualquier tupla, es posible acceder a los elementos por índice o recorrerlos con un bucle.
Toda tupla puramente numérica también se puede usar en funciones matemáticas como sum(), exactamente igual que los arrays.
Se puede desempaquetar una tupla en elementos individuales mediante la asignación múltiple.
Para los elementos que no necesites, usa el guion bajo _ como variable ficticia.
julia> tup = (1, "Julia", true)
(1, "Julia", true)
julia> num, name, _ = tup
(1, "Julia", true)
julia> uppercase(name), 2num
("JULIA", 2)
Para copiar todos los elementos de una tupla en otra tupla (o, más en general, en una colección), existe un operador splat ... que la desempaqueta.
Esto se tratará con más detalle en el concepto Funciones.
julia> new_tup = (tup..., π, '😊')
(1, "Julia", true, π, '😊')
Una Tuple solo contiene valores.
Una NamedTuple asocia cada valor con un nombre.
Después se puede acceder a los campos individuales con la notación de punto:
julia> nt = (a = 1, b = 7.3)
(a = 1, b = 7.3)
julia> dump(nt)
@NamedTuple{a::Int64, b::Float64}
a: Int64 1
b: Float64 7.3
julia> nt.b
7.3
El nombre se almacena internamente como un Symbol (un tipo inmutable, y el nombre va precedido de dos puntos :), así que también hay disponible una sintaxis alternativa:
julia> nt[:b]
7.3
A veces resulta útil dividir la creación de una tupla con nombre en dos pasos:
# Step 1
julia> Student = NamedTuple{(:name, :grade), Tuple{String, Int}}
@NamedTuple{name::String, grade::Int64}
julia> typeof(Student)
DataType
# Step 2
julia> s = Student( ("Helen", 3) )
(name = "Helen", grade = 3)
julia> dump(s)
@NamedTuple{name::String, grade::Int64}
name: String "Helen"
grade: Int64 3
Hay sorprendentemente muchas otras formas de crear una tupla con nombre, así que consulta la documentación si te interesa.
Es fácil obtener por separado los nombres (también llamados «claves») o los valores:
julia> keys(s)
(:name, :grade)
julia> values(s)
("Helen", 3)
Ten en cuenta que la iteración sobre una tupla con nombre solo produce los valores, y los nombres se ignoran.
Si los nombres también resultan útiles en una iteración, se necesitan más pasos.
La NamedTuple se puede convertir en un Vector de Pairs (los Pair son el tema de otro concepto).
julia> pairs(s)
pairs(::NamedTuple) with 2 entries:
:name => "Helen"
:grade => 3
julia> collect(pairs(s))
2-element Vector{Pair{Symbol, Any}}:
:name => "Helen"
:grade => 3
Así pues, la tupla con nombre es bastante similar a un diccionario.
Sin embargo, se diferencia de un [Dict][dict] de Julia en algunos aspectos importantes:
Dict es mutable; una NamedTuple, como cualquier tupla, es inmutable.Dict es flexible en el tipo de claves que acepta; una NamedTuple solo puede usar símbolos como claves.Las tuplas (con nombre o no) son una forma muy común de transferir datos estructurados hacia y desde funciones. La inmutabilidad es buena en este caso, ya que aporta seguridad a los datos y permite optimizaciones del compilador más agresivas.