Formátování prostého textu

Jazyk F# podporuje typově kontrolované formátování prostého textu pomocí printfprintfn, , sprintfa souvisejících funkcí. Příklad:

dotnet fsi

> printfn "Hello %s, %d + %d is %d" "world" 2 2 (2+2);;

poskytuje výstup.

Hello world, 2 + 2 is 4

Jazyk F# také umožňuje formátování strukturovaných hodnot jako prostý text. Představte si například následující příklad, který formátuje výstup jako zobrazení řazených kolekcí členů.

dotnet fsi

> printfn "%A" [ for i in 1 .. 5 -> [ for j in 1 .. 5 -> (i, j) ] ];;

[[(1, 1); (1, 2); (1, 3); (1, 4); (1, 5)];
 [(2, 1); (2, 2); (2, 3); (2, 4); (2, 5)];
 [(3, 1); (3, 2); (3, 3); (3, 4); (3, 5)];
 [(4, 1); (4, 2); (4, 3); (4, 4); (4, 5)];
 [(5, 1); (5, 2); (5, 3); (5, 4); (5, 5)]]

Formátování strukturovaného prostého %A textu se aktivuje při použití formátu v printf formátovacích řetězcích. Aktivuje se také při formátování výstupu hodnot v F# interactive, kde výstup obsahuje další informace a je navíc přizpůsobitelný. Formátování prostého textu je také pozorovatelné prostřednictvím všech volání x.ToString() sjednocovacích a záznamových hodnot jazyka F#, včetně těch, ke kterým dochází implicitně v ladění, protokolování a dalších nástrojích.

printfKontrola řetězců formátu

Chyba v době kompilace bude hlášena, pokud printf se funkce formátování používá s argumentem, který neodpovídá specifikátorům formátu printf v řetězci formátu. Příklad:

sprintf "Hello %s" (2+2)

poskytuje výstup.

  sprintf "Hello %s" (2+2)
  ----------------------^

stdin(3,25): error FS0001: The type 'string' does not match the type 'int'

Technicky vzato platí, že pokud používáte printf a další související funkce, speciální pravidlo v kompilátoru jazyka F# zkontroluje řetězcový literál předaný jako formátovací řetězec a zajistí, aby následné argumenty použité byly ve správném typu, aby odpovídaly specifikátorům formátu.

Specifikátory formátu pro printf

Specifikace formátu pro printf formáty jsou řetězce se značkami % , které označují formát. Zástupné symboly formátu se skládají z %[flags][width][.precision][type] toho, kde se typ interpretuje takto:

Specifikátor formátu Typy Poznámky
%b bool (System.Boolean) Formátovaný jako true nebo false
%s string (System.String) Naformátováno jako jeho nepotřebný obsah
%c char (System.Char) Naformátováno jako literál znaků
%d, %i základní celočíselné typy Formátováno jako desetinné celé číslo, podepsané, pokud je podepsaný základní celočíselná hodnota
%u základní celočíselné typy Formátováno jako celé číslo bez znaménka
%x, %X základní celočíselné typy Formátováno jako šestnáctkové číslo bez znaménka (a-f nebo A-F pro šestnáctkové číslice v uvedeném pořadí)
%o základní celočíselné typy Formátováno jako osmičkové číslo bez znaménka
%B základní celočíselné typy Formátováno jako binární číslo bez znaménka
%e, %E Základní typ s plovoucí desetinou čárkou Formátovaná jako hodnota se znaménkem s tvarem [-]d.dddde[sign]ddd , kde d je jedna desetinná číslice, dddd je jedna nebo více desetinných číslic, ddd je přesně tři desetinná čísla a znaménko je + nebo -
%f, %F Základní typ s plovoucí desetinou čárkou Naformátováno jako hodnota se signy, která má formulář [-]dddd.dddd, kde dddd je jedna nebo více desetinných míst. Počet číslic před desetinnou čárkou závisí na velikosti čísla a počet číslic za desetinnou čárkou závisí na požadované přesnosti.
%g, %G Základní typ s plovoucí desetinou čárkou Formátováno jako hodnota se signy vytištěnou ve %f formátu nebo %e ve formátu, podle toho, která zkomprimuje danou hodnotu a přesnost.
%M a decimal (System.Decimal) hodnota Formátováno pomocí specifikátoru "G" formátu pro System.Decimal.ToString(format)
%O libovolná hodnota Naformátováno polem objektu a voláním jeho System.Object.ToString() metody
%A libovolná hodnota Formátování pomocí formátování strukturovaného prostého textu s výchozím nastavením rozložení
%a libovolná hodnota Vyžaduje dva argumenty: funkce formátování, která přijímá kontextový parametr a hodnotu a konkrétní hodnotu k tisku.
%t libovolná hodnota Vyžaduje jeden argument: funkce formátování, která přijímá kontextový parametr, který buď vypíše, nebo vrátí odpovídající text.
%% (žádný) Nevyžaduje žádné argumenty a vytiskne znaménko prostého procenta: %

Základní celočíselné typy jsou byte (System.Byte), (System.SByte), int16sbyte (System.Int16), uint16 (System.UInt16), int32 (System.Int32), uint32 (System.UInt32), (System.Int64), int64 (), uint64 (System.UInt64), nativeint (System.IntPtr) a unativeint (System.UIntPtr). Základní typy s plovoucí desetinou čárkou jsou float (System.Double), float32 (System.Single) a decimal (System.Decimal).

Volitelná šířka je celé číslo označující minimální šířku výsledku. Například %6d vytiskne celé číslo s předponou mezerami, aby vyplnil alespoň šest znaků. Pokud je *šířka , pak se zadává další celočíselná hodnota, která určuje odpovídající šířku.

Platné příznaky jsou:

Příznak Účinnost
0 Přidání nul místo mezer pro vytvoření požadované šířky
- Doleva zarovnat výsledek do zadané šířky
+ Přidání znaku + , pokud je číslo kladné (aby odpovídalo znaménku - záporů)
znak mezery Pokud je číslo kladné (aby se shodovaly se znaménkem "-" pro záporné hodnoty, přidejte mezeru navíc).

Příznak printf # je neplatný a pokud se použije, zobrazí se chyba v době kompilace.

Hodnoty jsou formátovány pomocí invariantní jazykové verze. Nastavení jazykové verze je pro formátování irelevantní printf , s výjimkou případů, kdy mají vliv na výsledky %O formátování a %A formátování. Další informace najdete v tématu Formátování strukturovaného prostého textu.

%A Formátování

Specifikátor %A formátu se používá k formátování hodnot způsobem čitelným pro člověka a může být užitečný také pro vytváření sestav diagnostických informací.

Primitivní hodnoty

Při formátování prostého textu pomocí specifikátoru %A jsou číselné hodnoty jazyka F# formátovány s jejich příponou a neutrální jazykovou verzí. Hodnoty s plovoucí desetinnou čárkou jsou formátované pomocí 10 míst přesnosti s plovoucí desetinnou čárkou. Příklad:

printfn "%A" (1L, 3n, 5u, 7, 4.03f, 5.000000001, 5.0000000001)

Produkuje

(1L, 3n, 5u, 7, 4.03000021f, 5.000000001, 5.0)

Při použití specifikátoru %A jsou řetězce formátovány pomocí uvozovek. Řídicí kódy se nepřidají a místo toho se vytisknou nezpracované znaky. Příklad:

printfn "%A" ("abc", "a\tb\nc\"d")

Produkuje

("abc", "a      b
c"d")

Hodnoty .NET

Při formátování prostého textu pomocí specifikátoru %A jsou objekty .NET jiné než F# formátovány pomocí x.ToString() výchozích nastavení .NET zadaných System.Globalization.CultureInfo.CurrentCulture pomocí a System.Globalization.CultureInfo.CurrentUICulture. Příklad:

open System.Globalization

let date = System.DateTime(1999, 12, 31)

CultureInfo.CurrentCulture <- CultureInfo.GetCultureInfo("de-DE")
printfn "Culture 1: %A" date

CultureInfo.CurrentCulture <- CultureInfo.GetCultureInfo("en-US")
printfn "Culture 2: %A" date

Produkuje

Culture 1: 31.12.1999 00:00:00
Culture 2: 12/31/1999 12:00:00 AM

Strukturované hodnoty

Při formátování prostého textu pomocí specifikátoru %A se pro seznamy a řazené kolekce členů jazyka F# používá odsazení bloku. To je znázorněno v předchozím příkladu. Používá se také struktura polí, včetně multidimenzionálních polí. Jednorozměrná pole se zobrazují se [| ... |] syntaxí. Příklad:

printfn "%A" [| for i in 1 .. 20 -> (i, i*i) |]

Produkuje

[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25); (6, 36); (7, 49); (8, 64); (9, 81);
  (10, 100); (11, 121); (12, 144); (13, 169); (14, 196); (15, 225); (16, 256);
  (17, 289); (18, 324); (19, 361); (20, 400)|]

Výchozí šířka tisku je 80. Tuto šířku lze přizpůsobit pomocí šířky tisku ve specifikátoru formátu. Příklad:

printfn "%10A" [| for i in 1 .. 5 -> (i, i*i) |]

printfn "%20A" [| for i in 1 .. 5 -> (i, i*i) |]

printfn "%50A" [| for i in 1 .. 5 -> (i, i*i) |]

Produkuje

[|(1, 1);
  (2, 4);
  (3, 9);
  (4, 16);
  (5, 25)|]
[|(1, 1); (2, 4);
  (3, 9); (4, 16);
  (5, 25)|]
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]

Zadání šířky tisku 0 způsobí, že se nepoužívá žádná šířka tisku. Výsledkem bude jeden řádek textu, s výjimkou případů, kdy vložené řetězce ve výstupu obsahují konce řádků. Například

printfn "%0A" [| for i in 1 .. 5 -> (i, i*i) |]

printfn "%0A" [| for i in 1 .. 5 -> "abc\ndef" |]

Produkuje

[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]
[|"abc
def"; "abc
def"; "abc
def"; "abc
def"; "abc
def"|]

Limit hloubky 4 se používá pro sekvenční (IEnumerable) hodnoty, které jsou uvedeny jako seq { ...}. Pro hodnoty seznamu a matice se používá limit hloubky 100. Příklad:

printfn "%A" (seq { for i in 1 .. 10 -> (i, i*i) })

Produkuje

seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]

Odsazení bloku se používá také pro strukturu hodnot veřejného záznamu a sjednocení. Příklad:

type R = { X : int list; Y : string list }

printfn "%A" { X =  [ 1;2;3 ]; Y = ["one"; "two"; "three"] }

Produkuje

{ X = [1; 2; 3]
  Y = ["one"; "two"; "three"] }

Pokud %+A se použije, pak se pomocí reflexe odhalí také soukromá struktura záznamů a sjednocení. Například

type internal R =
    { X : int list; Y : string list }
    override _.ToString() = "R"

let internal data = { X = [ 1;2;3 ]; Y = ["one"; "two"; "three"] }

printfn "external view:\n%A" data

printfn "internal view:\n%+A" data

Produkuje

external view:
R

internal view:
{ X = [1; 2; 3]
  Y = ["one"; "two"; "three"] }

Velké, cyklické nebo hluboko vnořené hodnoty

Velké strukturované hodnoty jsou formátovány na maximální celkový počet uzlů objektu 1 0000. Hluboce vnořené hodnoty jsou formátovány na hloubku 100. V oboupřípadechch ... Příklad:

type Tree =
    | Tip
    | Node of Tree * Tree

let rec make n =
    if n = 0 then
        Tip
    else
        Node(Tip, make (n-1))

printfn "%A" (make 1000)

vytvoří velký výstup s některými částmi, které jsou elidovány:

Node(Tip, Node(Tip, ....Node (..., ...)...))

Cykly se detekují v grafech objektů a ... používají se na místech, kde jsou zjištěny cykly. Například

type R = { mutable Links: R list }
let r = { Links = [] }
r.Links <- [r]
printfn "%A" r

Produkuje

{ Links = [...] }

Opožděné hodnoty, hodnoty null a funkce

Opožděné hodnoty se vytisknou jako Value is not created nebo ekvivalentní text, pokud se hodnota ještě nevyhodnotila.

Hodnoty Null se vytisknou, pokud null není statický typ hodnoty určen jako typ sjednocení, kde null je povolené vyjádření.

Hodnoty funkce F# se vytisknou jako interně vygenerovaný název uzavření, <fun:it@43-7>například .

Přizpůsobení formátování prostého textu pomocí StructuredFormatDisplay

Při použití specifikátoru %A se respektuje přítomnost atributu StructuredFormatDisplay u deklarací typu. To lze použít k zadání náhradního textu a vlastnosti k zobrazení hodnoty. Příklad:

[<StructuredFormatDisplay("Counts({Clicks})")>]
type Counts = { Clicks:int list}

printfn "%20A" {Clicks=[0..20]}

Produkuje

Counts([0; 1; 2; 3;
        4; 5; 6; 7;
        8; 9; 10; 11;
        12; 13; 14;
        15; 16; 17;
        18; 19; 20])

Přizpůsobení formátování prostého textu přepsáním ToString

Výchozí implementace je pozorovatelná v programování jazyka ToString F#. Výchozí výsledky často nejsou vhodné pro použití v zobrazení informací určených programátorem nebo výstupu uživatele a v důsledku toho je běžné přepsat výchozí implementaci.

Ve výchozím nastavení přepisují typy záznamů a sjednocení jazyka F# implementaci ToString s implementací, která používá sprintf "%+A". Příklad:

type Counts = { Clicks:int list }

printfn "%s" ({Clicks=[0..10]}.ToString())

Produkuje

{ Clicks = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] }

U typů tříd není zadána žádná výchozí implementace ToString a používá se výchozí hodnota .NET, která hlásí název typu. Příklad:

type MyClassType(clicks: int list) =
   member _.Clicks = clicks

let data = [ MyClassType([1..5]); MyClassType([1..5]) ]
printfn "Default structured print gives this:\n%A" data
printfn "Default ToString gives:\n%s" (data.ToString())

Produkuje

Default structured print gives this:
[MyClassType; MyClassType]
Default ToString gives:
[MyClassType; MyClassType]

Přidání přepsání může ToString poskytnout lepší formátování.

type MyClassType(clicks: int list) =
   member _.Clicks = clicks
   override _.ToString() = sprintf "MyClassType(%0A)" clicks

let data = [ MyClassType([1..5]); MyClassType([1..5]) ]
printfn "Now structured print gives this:\n%A" data
printfn "Now ToString gives:\n%s" (data.ToString())

Produkuje

Now structured print gives this:
[MyClassType([1; 2; 3; 4; 5]); MyClassType([1; 2; 3; 4; 5])]
Now ToString gives:
[MyClassType([1; 2; 3; 4; 5]); MyClassType([1; 2; 3; 4; 5])]

Přizpůsobení formátování prostého textu pomocí StructuredFormatDisplay a ToString

Pokud chcete dosáhnout konzistentního formátování specifikátorů %A a %O specifikátorů formátu, zkombinujte použití StructuredFormatDisplay s přepsáním ToString. Příklad:

[<StructuredFormatDisplay("{DisplayText}")>]
type MyRecord =
    {
        a: int
    }
    member this.DisplayText = this.ToString()

    override _.ToString() = "Custom ToString"

Vyhodnocení následujících definic

let myRec = { a = 10 }
let myTuple = (myRec, myRec)
let s1 = sprintf $"{myRec}"
let s2 = sprintf $"{myTuple}"
let s3 = sprintf $"%A{myTuple}"
let s4 = sprintf $"{[myRec; myRec]}"
let s5 = sprintf $"%A{[myRec; myRec]}"

vrátí text.

val myRec: MyRecord = Custom ToString
val myTuple: MyRecord * MyRecord = (Custom ToString, Custom ToString)
val s1: string = "Custom ToString"
val s2: string = "(Custom ToString, Custom ToString)"
val s3: string = "(Custom ToString, Custom ToString)"
val s4: string = "[Custom ToString; Custom ToString]"
val s5: string = "[Custom ToString; Custom ToString]"

Použití podpůrné DisplayText vlastnosti znamená skutečnost, že myRec je typ strukturálního StructuredFormatDisplay záznamu ignorován během strukturovaného ToString() tisku a přepsání je preferováno za všech okolností.

Implementaci System.IFormattable rozhraní lze přidat pro další přizpůsobení v přítomnosti specifikací formátu .NET.

F# Interactive strukturovaný tisk

F# Interactive (dotnet fsi) používá rozšířenou verzi formátování strukturovaného prostého textu k hodnotám sestavy a umožňuje další přizpůsobení. Další informace najdete v tématu F# Interactive.

Přizpůsobení zobrazení ladění

Ladicí programy pro .NET respektují použití atributů, jako DebuggerDisplay jsou a DebuggerTypeProxy, a tyto ovlivňují strukturované zobrazení objektů v kontrolních oknech ladicího programu. Kompilátor jazyka F# tyto atributy automaticky vygeneroval pro diskriminované typy sjednocení a záznamů, ale ne pro třídy, rozhraní nebo typy struktur.

Tyto atributy jsou ignorovány ve formátování prostého textu jazyka F#, ale může být užitečné implementovat tyto metody ke zlepšení zobrazení při ladění typů jazyka F#.

Viz také