Ricerca…


Sintassi

  • un,
  • a, b
  • a, b = xs
  • ()
  • (un,)
  • (a, b)
  • (a, b ...)
  • Tupla {T, U, V}
  • NTuple {N, T}
  • Tupla {T, U, Vararg {V}}

Osservazioni

Le tuple hanno prestazioni di runtime molto migliori degli array per due motivi: i loro tipi sono più precisi e la loro immutabilità consente loro di essere allocati nello stack anziché nell'heap. Tuttavia, questa digitazione più precisa viene fornita con un overhead in più tempo di compilazione e maggiori difficoltà nel raggiungere la stabilità del tipo .

Introduzione a Tuples

Tuple sono collezioni ordinate immutabili di oggetti distinti arbitrari, dello stesso tipo o di tipi diversi. Tipicamente, le tuple sono costruite usando la sintassi (x, y) .

julia> tup = (1, 1.0, "Hello, World!")
(1,1.0,"Hello, World!")

I singoli oggetti di una tupla possono essere recuperati usando la sintassi dell'indicizzazione:

julia> tup[1]
1

julia> tup[2]
1.0

julia> tup[3]
"Hello, World!"

Implementano l' interfaccia iterabile e possono quindi essere iterati utilizzando loop for :

julia> for item in tup
           println(item)
       end
1
1.0
Hello, World!

Le tuple supportano anche una varietà di funzioni di collezioni generiche, come il reverse o la length :

julia> reverse(tup)
("Hello, World!",1.0,1)

julia> length(tup)
3

Inoltre, le tuple supportano una varietà di operazioni di raccolta di ordine superiore , incluse any , all , map o 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

La tupla vuota può essere costruita usando () :

julia> ()
()

julia> isempty(ans)
true

Tuttavia, per costruire una tupla di un elemento, è necessaria una virgola finale. Questo perché le parentesi ( ( e ) ) sarebbero altrimenti trattate come operazioni di raggruppamento insieme invece di costruire una tupla.

julia> (1)
1

julia> (1,)
(1,)

Per coerenza, una virgola finale è anche consentita per le tuple con più di un elemento.

julia> (1, 2, 3,)
(1,2,3)

Tipi di tupla

Il typeof una tupla è un sottotipo di Tuple :

julia> typeof((1, 2, 3))
Tuple{Int64,Int64,Int64}

julia> typeof((1.0, :x, (1, 2)))
Tuple{Float64,Symbol,Tuple{Int64,Int64}}

A differenza di altri tipi di dati, i tipi di Tuple sono covarianti . Altri tipi di dati in Julia sono generalmente invarianti. Così,

julia> Tuple{Int, Int} <: Tuple{Number, Number}
true

julia> Vector{Int} <: Vector{Number}
false

Questo è il caso perché ovunque sia accettata una Tuple{Number, Number} , così anche una Tuple{Int, Int} , poiché ha anche due elementi, entrambi sono numeri. Questo non è il caso di un Vector{Int} contro un Vector{Number} , in quanto una funzione che accetta un Vector{Number} può desiderare di memorizzare un punto mobile (es. 1.0 ) o un numero complesso (ad esempio 1+3im ) in tale un vettore

La covarianza dei tipi di tupla significa che Tuple{Number} (a differenza di Vector{Number} ) è in realtà un tipo astratto:

julia> isleaftype(Tuple{Number})
false

julia> isleaftype(Vector{Number})
true

I sottotipi concreti di Tuple{Number} includono Tuple{Int} , Tuple{Float64} , Tuple{Rational{BigInt}} e così via.

Tuple tipi di Vararg possono contenere un Vararg terminazione come ultimo parametro per indicare un numero indefinito di oggetti. Ad esempio, Tuple{Vararg{Int}} è il tipo di tutte le tuple che contengono un numero qualsiasi di Int s, possibilmente zero:

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

mentre Tuple{String, Vararg{Int}} accetta tuple costituite da una stringa , seguite da qualsiasi numero (possibilmente zero) di Int s.

julia> isa(("x", 1, 2), Tuple{String, Vararg{Int}})
true

julia> isa((1, 2), Tuple{String, Vararg{Int}})
false

Combinato con co-varianza, ciò significa che Tuple{Vararg{Any}} descrive qualsiasi tupla. In effetti, Tuple{Vararg{Any}} è solo un altro modo di dire Tuple :

julia> Tuple{Vararg{Any}} == Tuple
true

Vararg accetta un secondo parametro di tipo numerico che indica quante volte dovrebbe verificarsi esattamente il suo primo parametro di tipo. (Per default, se non specificato, questo secondo parametro tipo è un typevar che può assumere qualsiasi valore, motivo per cui un numero qualsiasi di Int s sono accettato nella Vararg s sopra.) Tuple tipi terminanti in un determinato Vararg verrà automaticamente esteso al numero richiesto di elementi:

julia> Tuple{String,Vararg{Int, 3}}
Tuple{String,Int64,Int64,Int64}

Esiste una notazione per tuple omogenee con un Vararg specificato: NTuple{N, T} . In questa notazione, N indica il numero di elementi nella tupla e T indica il tipo accettato. Per esempio,

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)

Nota che NTuple s oltre una certa dimensione viene mostrato semplicemente come NTuple{N, T} , invece del modulo Tuple espanso, ma sono sempre dello stesso tipo:

julia> Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int}
NTuple{10,Int64}

Dispacciamento di tipi di tuple

Poiché gli elenchi dei parametri della funzione di Julia sono essi stessi delle tuple, l' invio di vari tipi di tuple è spesso più semplice attraverso i parametri del metodo stessi, spesso con un uso liberale per l'operatore "splatting" ... Ad esempio, considera l'implementazione del reverse per le tuple, da Base :

revargs() = ()
revargs(x, r...) = (revargs(r...)..., x)

reverse(t::Tuple) = revargs(t...)

L'implementazione dei metodi sulle tuple in questo modo preserva la stabilità del tipo , che è fondamentale per le prestazioni. Possiamo vedere che non c'è nessun overhead a questo approccio usando 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}

Anche se un po 'difficile da leggere, il codice qui sta semplicemente creando una nuova tupla con valori 3 °, 2 ° e 1 ° elementi della tupla originale, rispettivamente. Su molte macchine, questo compila verso il codice LLVM estremamente efficiente, che consiste in carichi e negozi.

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
}

Più valori di ritorno

Le tuple sono spesso utilizzate per valori di ritorno multipli. Gran parte della libreria standard, incluse due delle funzioni dell'interfaccia iterabile ( next e done ), restituisce tuple contenenti due valori correlati ma distinti.

Le parentesi attorno alle tuple possono essere omesse in determinate situazioni, rendendo più facili da implementare più valori di ritorno. Ad esempio, possiamo creare una funzione per restituire sia radici quadrate positive che negative di un numero reale:

julia> pmsqrt(x::Real) = sqrt(x), -sqrt(x)
pmsqrt (generic function with 1 method)

julia> pmsqrt(4)
(2.0,-2.0)

L'assegnazione della distruzione può essere utilizzata per decomprimere i valori di ritorno multipli. Per memorizzare le radici quadrate nelle variabili a e b , è sufficiente scrivere:

julia> a, b = pmsqrt(9.0)
(3.0,-3.0)

julia> a
3.0

julia> b
-3.0

Un altro esempio di ciò sono le funzioni divrem e fldmod , che eseguono contemporaneamente una divisione intera (troncata o pavimentata) e un'operazione resto:

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow