Julia Language
Tuples
Recherche…
Syntaxe
- une,
- un B
- a, b = xs
- ()
- (une,)
- (un B)
- (un B...)
- Tuple {T, U, V}
- NTuple {N, T}
- Tuple {T, U, Vararg {V}}
Remarques
Les tuples ont de meilleures performances d'exécution que les tableaux pour deux raisons: leurs types sont plus précis et leur immuabilité leur permet d'être alloués sur la pile au lieu du tas. Cependant, cette saisie plus précise s'accompagne d'un temps système plus long au moment de la compilation et de plus de difficultés à atteindre la stabilité du type .
Introduction aux tuples
Tuple
sont des collections ordonnées immuables d'objets distincts arbitraires, du même type ou de types différents. Généralement, les tuples sont construits en utilisant la syntaxe (x, y)
.
julia> tup = (1, 1.0, "Hello, World!")
(1,1.0,"Hello, World!")
Les objets individuels d'un tuple peuvent être récupérés à l'aide de la syntaxe d'indexation:
julia> tup[1]
1
julia> tup[2]
1.0
julia> tup[3]
"Hello, World!"
Ils implémentent l' interface itérable , et peuvent donc être itérés en utilisant for
boucles for
:
julia> for item in tup
println(item)
end
1
1.0
Hello, World!
Les tuples prennent également en charge diverses fonctions de collections génériques, telles que l' reverse
ou la length
:
julia> reverse(tup)
("Hello, World!",1.0,1)
julia> length(tup)
3
De plus, les n-uplets prennent en charge diverses opérations de collecte de niveau supérieur , y compris any
, all
, all
map
ou toutes les broadcast
:
julia> map(typeof, tup)
(Int64,Float64,String)
julia> all(x -> x < 2, (1, 2, 3))
false
julia> all(x -> x < 4, (1, 2, 3))
true
julia> any(x -> x < 2, (1, 2, 3))
true
Le tuple vide peut être construit en utilisant ()
:
julia> ()
()
julia> isempty(ans)
true
Cependant, pour construire un tuple d'un élément, une virgule est requise. C'est parce que les parenthèses ( (
et )
) seraient autrement traitées comme des opérations de regroupement au lieu de construire un tuple.
julia> (1)
1
julia> (1,)
(1,)
Par souci de cohérence, une virgule de fin est également autorisée pour les tuples comportant plusieurs éléments.
julia> (1, 2, 3,)
(1,2,3)
Types de tuple
Le typeof
un tuple est un sous-type de Tuple
:
julia> typeof((1, 2, 3))
Tuple{Int64,Int64,Int64}
julia> typeof((1.0, :x, (1, 2)))
Tuple{Float64,Symbol,Tuple{Int64,Int64}}
Contrairement aux autres types de données, les types de Tuple
sont covariants . Les autres types de données dans Julia sont généralement invariants. Ainsi,
julia> Tuple{Int, Int} <: Tuple{Number, Number}
true
julia> Vector{Int} <: Vector{Number}
false
C'est le cas parce que partout un Tuple{Number, Number}
est accepté, tout comme un Tuple{Int, Int}
, car il comporte également deux éléments, les deux étant des nombres. Ce n'est pas le cas pour un Vector{Int}
par rapport à un Vector{Number}
, car une fonction acceptant un Vector{Number}
peut souhaiter stocker un point flottant (par exemple 1.0
) ou un nombre complexe (par exemple 1+3im
). un vecteur.
La covariance des types de tuple signifie que Tuple{Number}
(contrairement à Vector{Number}
) est en réalité un type abstrait:
julia> isleaftype(Tuple{Number})
false
julia> isleaftype(Vector{Number})
true
Les sous-types concrets de Tuple{Number}
incluent Tuple{Int}
, Tuple{Float64}
, Tuple{Float64}
Tuple{Rational{BigInt}}
, etc.
Tuple
types de Tuple
peuvent contenir une terminaison de Vararg
comme dernier paramètre pour indiquer un nombre indéfini d'objets. Par exemple, Tuple{Vararg{Int}}
est le type de tous les n-uplets contenant un nombre quelconque de s Int
, éventuellement nul:
julia> isa((), Tuple{Vararg{Int}})
true
julia> isa((1,), Tuple{Vararg{Int}})
true
julia> isa((1,2,3,4,5), Tuple{Vararg{Int}})
true
julia> isa((1.0,), Tuple{Vararg{Int}})
false
alors que Tuple{String, Vararg{Int}}
accepte les tuples constitués d'une chaîne , suivis de tout nombre (éventuellement nul) de Int
s.
julia> isa(("x", 1, 2), Tuple{String, Vararg{Int}})
true
julia> isa((1, 2), Tuple{String, Vararg{Int}})
false
Combiné à la co-variance, cela signifie que Tuple{Vararg{Any}}
décrit un tuple. En effet, Tuple{Vararg{Any}}
est une autre façon de dire Tuple
:
julia> Tuple{Vararg{Any}} == Tuple
true
Vararg
accepte un second paramètre de type numérique indiquant combien de fois exactement son paramètre de premier type doit apparaître. (Par défaut, si non précisé, ce second paramètre de type est un TypeVar qui peut prendre toute valeur, ce qui est la raison pour laquelle un certain nombre de Int
s sont acceptés dans le Vararg
de ci - dessus.) Tuple
types se terminant dans un spécifié Vararg
sera automatiquement étendu à la nombre d'éléments requis:
julia> Tuple{String,Vararg{Int, 3}}
Tuple{String,Int64,Int64,Int64}
La notation existe pour les tuples homogènes avec un Vararg
spécifié: NTuple{N, T}
. Dans cette notation, N
désigne le nombre d'éléments dans le tuple et T
désigne le type accepté. Par exemple,
julia> NTuple{3, Int}
Tuple{Int64,Int64,Int64}
julia> NTuple{10, Int}
NTuple{10,Int64}
julia> ans.types
svec(Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64)
Notez que les NTuple
au-delà d'une certaine taille sont simplement affichés comme NTuple{N, T}
, au lieu de la forme Tuple
développée, mais ils sont toujours du même type:
julia> Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int}
NTuple{10,Int64}
Envoi sur types de tuple
Étant donné que la liste des paramètres de la fonction Julia sont eux - mêmes tuples, l' envoi de différents types de tuples est souvent plus facile fait par la méthode des paramètres eux - mêmes, souvent avec l' utilisation libérale de la « splatting » ...
opérateur. Par exemple, considérez l'implémentation de reverse
pour tuples, à partir de la Base
:
revargs() = ()
revargs(x, r...) = (revargs(r...)..., x)
reverse(t::Tuple) = revargs(t...)
Implémenter des méthodes sur des tuples de cette manière préserve la stabilité de type , ce qui est crucial pour les performances. Nous pouvons voir qu'il n'y a pas de surcharge à cette approche en utilisant la macro @code_warntype
:
julia> @code_warntype reverse((1, 2, 3))
Variables:
#self#::Base.#reverse
t::Tuple{Int64,Int64,Int64}
Body:
begin
SSAValue(1) = (Core.getfield)(t::Tuple{Int64,Int64,Int64},2)::Int64
SSAValue(2) = (Core.getfield)(t::Tuple{Int64,Int64,Int64},3)::Int64
return (Core.tuple)(SSAValue(2),SSAValue(1),(Core.getfield)(t::Tuple{Int64,Int64,Int64},1)::Int64)::Tuple{Int64,Int64,Int64}
end::Tuple{Int64,Int64,Int64}
Bien que difficile à lire, le code crée simplement un nouveau tuple avec les valeurs 3, 2 et 1 du tuple original, respectivement. Sur de nombreuses machines, cela se traduit par un code LLVM extrêmement efficace, composé de charges et de magasins.
julia> @code_llvm reverse((1, 2, 3))
define void @julia_reverse_71456([3 x i64]* noalias sret, [3 x i64]*) #0 {
top:
%2 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 1
%3 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 2
%4 = load i64, i64* %3, align 1
%5 = load i64, i64* %2, align 1
%6 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 0
%7 = load i64, i64* %6, align 1
%.sroa.0.0..sroa_idx = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 0
store i64 %4, i64* %.sroa.0.0..sroa_idx, align 8
%.sroa.2.0..sroa_idx1 = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 1
store i64 %5, i64* %.sroa.2.0..sroa_idx1, align 8
%.sroa.3.0..sroa_idx2 = getelementptr inbounds [3 x i64], [3 x i64]* %0, i64 0, i64 2
store i64 %7, i64* %.sroa.3.0..sroa_idx2, align 8
ret void
}
Plusieurs valeurs de retour
Les tuples sont fréquemment utilisés pour plusieurs valeurs de retour. Une grande partie de la bibliothèque standard, y compris deux des fonctions de l' interface itérable ( next
and done
), renvoie des tuples contenant deux valeurs liées mais distinctes.
Les parenthèses autour des tuples peuvent être omises dans certaines situations, ce qui facilite l'implémentation de plusieurs valeurs de retour. Par exemple, nous pouvons créer une fonction pour renvoyer à la fois les racines carrées positives et négatives d'un nombre réel:
julia> pmsqrt(x::Real) = sqrt(x), -sqrt(x)
pmsqrt (generic function with 1 method)
julia> pmsqrt(4)
(2.0,-2.0)
L'affectation de destruction peut être utilisée pour décompresser les valeurs de retour multiples. Pour stocker les racines carrées dans les variables a
et b
, il suffit d'écrire:
julia> a, b = pmsqrt(9.0)
(3.0,-3.0)
julia> a
3.0
julia> b
-3.0
Un autre exemple est les fonctions divrem
et fldmod
, qui effectuent une division entière (respectivement divrem
ou fldmod
) et une opération de reste en même temps:
julia> q, r = divrem(10, 3)
(3,1)
julia> q
3
julia> r
1