Formátování prostého textu
Jazyk F# podporuje typově kontrolované formátování prostého textu pomocí printf
printfn
, , sprintf
a 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.
printf
Kontrola ř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
), int16
sbyte
(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#.