Sök…


Syntax

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

Anmärkningar

Tuples har mycket bättre runtime-prestanda än matriser av två skäl: deras typer är mer exakta, och deras immutabilitet gör att de kan fördelas på stacken istället för högen. Men den mer exakta typen kommer med både mer kompileringstidskostnader och svårare att uppnå typstabilitet .

Introduktion till Tuples

Tuple är oföränderliga ordnade samlingar av godtyckliga distinkta objekt, antingen av samma typ eller av olika typer . Vanligtvis är tuples konstruerade med (x, y) syntax.

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

De enskilda objekten i en tupel kan hämtas med indexeringssyntax:

julia> tup[1]
1

julia> tup[2]
1.0

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

De implementerar det iterabla gränssnittet och kan därför itereras över att använda for slingor :

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

Tuples stöder också en mängd olika generiska kollektionsfunktioner, till exempel reverse eller length :

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

julia> length(tup)
3

Dessutom stöder tuples en mängd olika ordningar med högre ordning , inklusive any , all , map eller 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

Den tomma tupeln kan konstrueras med () :

julia> ()
()

julia> isempty(ans)
true

För att konstruera en tupel av ett element krävs emellertid en efterföljande komma. Detta beror på att parenteserna ( ( och ) ) annars skulle behandlas som grupperingar i stället för att konstruera en tupel.

julia> (1)
1

julia> (1,)
(1,)

För konsistens tillåts också en efterföljande komma för tupler med mer än ett element.

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

Tupeltyper

typeof en tupel är en subtyp av Tuple :

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

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

Till skillnad från andra datatyper är Tuple typer kovarianta . Andra datatyper i Julia är i allmänhet invariant. Således,

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

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

Detta är fallet eftersom överallt en Tuple{Number, Number} accepteras, också en Tuple{Int, Int} , eftersom den också har två element, som båda är nummer. Det är inte fallet för en Vector{Int} kontra en Vector{Number} , eftersom en funktion som accepterar en Vector{Number} kanske vill lagra en flytande punkt (t.ex. 1.0 ) eller ett komplext nummer (t.ex. 1+3im ) i sådan en vektor.

Överensstämmelsen mellan tupeltyper innebär att Tuple{Number} (igen till skillnad från Vector{Number} ) faktiskt är en abstrakt typ:

julia> isleaftype(Tuple{Number})
false

julia> isleaftype(Vector{Number})
true

Konkreta undertyper av Tuple{Number} inkluderar Tuple{Int} , Tuple{Float64} , Tuple{Rational{BigInt}} och så vidare.

Tuple kan innehålla en avslutande Vararg som deras sista parameter för att indikera ett obestämt antal objekt. Till exempel är Tuple{Vararg{Int}} typen av alla tupler som innehåller valfritt antal Int , eventuellt noll:

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

Medan Tuple{String, Vararg{Int}} accepterar tuples som består av en sträng , följt av valfritt antal (möjligen noll) Int .

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

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

Kombinerat med co-varians betyder detta att Tuple{Vararg{Any}} beskriver vilken tupel som helst. Faktum är att Tuple{Vararg{Any}} bara är ett annat sätt att säga Tuple :

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

Vararg accepterar en andra parameter för numerisk typ som anger hur många gånger exakt den första typparametern ska inträffa. (Som standard, om ospecificerade, är denna andra typ parametern en typevar som kan ta vilket som helst värde, varför varje antal Int s accepteras i Vararg s ovan.) Tuple typer som slutar i ett specificerat Vararg automatiskt utvidgas till önskat antal element:

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

Det finns notering för homogena tupler med en specifik Vararg : NTuple{N, T} . I denna notering betecknar N antalet element i tupeln och T anger den accepterade typen. Till exempel,

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)

Observera att NTuple s utöver en viss storlek visas helt enkelt som NTuple{N, T} , i stället för den utvidgade Tuple formen, men de är fortfarande av samma typ:

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

Skickas på tupeltyper

Eftersom Julia-funktionsparameterlistorna själva är tuplar, är det ofta lättare att skicka ut olika typer av tupplar genom själva metodparametrarna, ofta med liberal användning för operatören "splitting" ... Tänk till exempel på implementeringen av reverse för tuples, från Base :

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

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

Genomförande av metoder på tupplar på detta sätt bevarar typstabilitet , vilket är avgörande för prestanda. Vi kan se att det inte finns några omkostnader för den här metoden med hjälp av makro @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}

Även om det är svårt att läsa, är koden här helt enkelt att skapa en ny tupel med värden 3: e, 2: a och 1: a elementen i den ursprungliga tupeln. På många maskiner sammanställs detta till extremt effektiv LLVM-kod, som består av laster och butiker.

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
}

Flera returvärden

Tuples används ofta för flera värden på retur. Mycket av standardbiblioteket, inklusive två av funktionerna för det iterable gränssnittet ( next och done ), returnerar tuples som innehåller två relaterade men distinkta värden.

Parenteserna kring tuplerna kan utelämnas i vissa situationer, vilket gör att flera värden för retur är enklare att implementera. Vi kan till exempel skapa en funktion för att returnera både positiva och negativa kvadratrötter av ett reellt tal:

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

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

Destruktureringsuppdrag kan användas för att packa upp flera värden för retur. För att lagra kvadratroten i variablerna a och b räcker det att skriva:

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

julia> a
3.0

julia> b
-3.0

Ett annat exempel på detta är divrem och fldmod funktionerna, som gör en heltal (trunkering respektive floored), delning och återstående operation samtidigt:

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow