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


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow