Opmaak van tekst zonder opmaak
F# ondersteunt door het type gecontroleerd opmaak van tekst zonder opmaak met behulp van printf
, printfn
en sprintf
gerelateerde functies.
Bijvoorbeeld:
dotnet fsi
> printfn "Hello %s, %d + %d is %d" "world" 2 2 (2+2);;
geeft de uitvoer
Hello world, 2 + 2 is 4
Met F# kunnen gestructureerde waarden ook worden opgemaakt als tekst zonder opmaak. Bekijk bijvoorbeeld het volgende voorbeeld waarmee de uitvoer wordt opgemaakt als een matrixachtige weergave van tuples.
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)]]
Gestructureerde tekstopmaak zonder opmaak wordt geactiveerd wanneer u de %A
opmaak in printf
opmaaktekenreeksen gebruikt.
Het wordt ook geactiveerd bij het opmaken van de uitvoer van waarden in F# interactief, waarbij de uitvoer extra informatie bevat en ook kan worden aangepast.
Opmaak van tekst zonder opmaak is ook waarneembaar via aanroepen van x.ToString()
F#-samenvoegings- en recordwaarden, inclusief waarden die impliciet voorkomen in foutopsporing, logboekregistratie en andere hulpprogramma's.
Controleren van printf
tekenreeksen opmaken
Er wordt een compilatiefout gerapporteerd als een printf
opmaakfunctie wordt gebruikt met een argument dat niet overeenkomt met de opmaakaanduidingen van de afdrukf in de notatietekenreeks. Bijvoorbeeld:
sprintf "Hello %s" (2+2)
geeft de uitvoer
sprintf "Hello %s" (2+2)
----------------------^
stdin(3,25): error FS0001: The type 'string' does not match the type 'int'
Technisch gesproken controleert een speciale regel in de F#-compiler bij het gebruik van printf
en andere gerelateerde functies de letterlijke tekenreeks die wordt doorgegeven als de notatietekenreeks, zodat de volgende argumenten van het juiste type overeenkomen met de gebruikte notatieaanduidingen.
Opmaakaanduidingen voor printf
Indelingsspecificaties voor printf
notaties zijn tekenreeksen met %
markeringen die de opmaak aangeven. Tijdelijke aanduidingen opmaken, bestaat uit %[flags][width][.precision][type]
de manier waarop het type als volgt wordt geïnterpreteerd:
Opmaakaanduiding | Type(n) | Opmerkingen |
---|---|---|
%b |
bool (System.Boolean ) |
Opgemaakt als true of false |
%s |
string (System.String ) |
Opgemaakt als niet-gescaped inhoud |
%c |
char (System.Char ) |
Opgemaakt als letterlijk teken |
%d , %i |
een eenvoudig geheel getaltype | Opgemaakt als een decimaal geheel getal, ondertekend als het basistype geheel getal is ondertekend |
%u |
een eenvoudig geheel getaltype | Opgemaakt als een niet-ondertekend decimaal geheel getal |
%x , %X |
een eenvoudig geheel getaltype | Opgemaakt als een niet-ondertekend hexadecimaal getal (respectievelijk a-f of A-F voor hexe cijfers) |
%o |
een eenvoudig geheel getaltype | Opgemaakt als een niet-ondertekend octaal getal |
%B |
een eenvoudig geheel getaltype | Opgemaakt als een niet-ondertekend binair getal |
%e , %E |
een basistype voor drijvende komma | Opgemaakt als een ondertekende waarde met het formulier [-]d.dddde[sign]ddd waarbij d één decimaalteken is, is dddd een of meer decimale cijfers, ddd precies drie decimale cijfers en teken is + of - |
%f , %F |
een basistype voor drijvende komma | Opgemaakt als een ondertekende waarde met het formulier [-]dddd.dddd , waarbij dddd een of meer decimale cijfers zijn. Het aantal cijfers vóór het decimaalteken is afhankelijk van de grootte van het getal en het aantal cijfers na het decimaalteken is afhankelijk van de aangevraagde precisie. |
%g , %G |
een basistype voor drijvende komma | Opgemaakt met behulp van een ondertekende waarde die wordt afgedrukt in %f of %e opgemaakt, afhankelijk van wat compacter is voor de opgegeven waarde en precisie. |
%M |
a decimal (System.Decimal ) waarde |
Opgemaakt met de "G" notatieaanduiding voor System.Decimal.ToString(format) |
%O |
elke waarde | Opgemaakt door het object te boksen en de methode aan System.Object.ToString() te roepen |
%A |
elke waarde | Opgemaakt met gestructureerde tekstopmaak zonder opmaak met de standaardindelingsinstellingen |
%a |
elke waarde | Hiervoor zijn twee argumenten vereist: een opmaakfunctie die een contextparameter en de waarde accepteert, en de specifieke waarde die moet worden afgedrukt |
%t |
elke waarde | Vereist één argument: een opmaakfunctie die een contextparameter accepteert die de juiste tekst uitvoert of retourneert |
%% |
(geen) | Hiervoor zijn geen argumenten vereist en wordt een gewoon procentteken afgedrukt: % |
Typen basis gehele getallen zijn byte
(), (System.Byte
), sbyte
(System.SByte
), int16
uint16
(System.Int16
), (System.UInt16
), int32
(System.Int32
), uint32
(System.UInt32
), (), int64
(System.Int64
), uint64
(System.UInt64
System.IntPtr
) nativeint
en unativeint
(System.UIntPtr
).
Basistypen voor drijvende komma zijn float
(), float32
(System.Double
System.Single
) en decimal
(System.Decimal
).
De optionele breedte is een geheel getal dat de minimale breedte van het resultaat aangeeft. Hiermee drukt u bijvoorbeeld %6d
een geheel getal af, waarbij het wordt voorafgegaan door spaties om ten minste zes tekens in te vullen. Als de breedte is *
, wordt een extra geheel getal gebruikt om de bijbehorende breedte op te geven.
Geldige vlaggen zijn:
Vlag | Effect |
---|---|
0 |
Nullen toevoegen in plaats van spaties om de vereiste breedte te vormen |
- |
Links het resultaat binnen de opgegeven breedte uitvullen |
+ |
Voeg een + teken toe als het getal positief is (om een - teken voor negatieven te vinden) |
spatieteken | Voeg een extra spatie toe als het getal positief is (om overeen te komen met een '-' teken voor negatieven) |
De vlag printf #
is ongeldig en er wordt een compilatiefout gerapporteerd als deze wordt gebruikt.
Waarden worden opgemaakt met behulp van invariante cultuur. Cultuurinstellingen zijn niet relevant voor printf
opmaak, behalve wanneer deze van invloed zijn op de resultaten en %O
%A
opmaak. Zie gestructureerde tekstopmaak zonder opmaak voor meer informatie.
%A
Opmaak
De %A
indelingsaanduiding wordt gebruikt om waarden op een door mensen leesbare manier op te maken en kan ook handig zijn voor het rapporteren van diagnostische gegevens.
Primitieve waarden
Wanneer u tekst zonder opmaak opmaakt met de %A
aanduiding, worden F#-numerieke waarden opgemaakt met het achtervoegsel en de invariante cultuur. Drijvende-kommawaarden worden opgemaakt met behulp van 10 plaatsen met precisie van drijvende komma. Bijvoorbeeld:
printfn "%A" (1L, 3n, 5u, 7, 4.03f, 5.000000001, 5.0000000001)
Produceert
(1L, 3n, 5u, 7, 4.03000021f, 5.000000001, 5.0)
Wanneer u de %A
aanduiding gebruikt, worden tekenreeksen opgemaakt met aanhalingstekens. Escapecodes worden niet toegevoegd en in plaats daarvan worden de onbewerkte tekens afgedrukt. Bijvoorbeeld:
printfn "%A" ("abc", "a\tb\nc\"d")
Produceert
("abc", "a b
c"d")
.NET-waarden
Wanneer u tekst zonder opmaak opmaakt met behulp van de %A
aanduiding, worden niet-F# .NET-objecten opgemaakt met behulp van x.ToString()
de standaardinstellingen van .NET gegeven door System.Globalization.CultureInfo.CurrentCulture
en System.Globalization.CultureInfo.CurrentUICulture
. Bijvoorbeeld:
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
Produceert
Culture 1: 31.12.1999 00:00:00
Culture 2: 12/31/1999 12:00:00 AM
Gestructureerde waarden
Wanneer u tekst zonder opmaak opmaakt met de %A
aanduiding, wordt blok inspringing gebruikt voor F#-lijsten en tuples. Dit wordt weergegeven in het vorige voorbeeld.
De structuur van matrices wordt ook gebruikt, waaronder multidimensionale matrices. Eendimensionale matrices worden weergegeven met [| ... |]
syntaxis. Bijvoorbeeld:
printfn "%A" [| for i in 1 .. 20 -> (i, i*i) |]
Produceert
[|(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)|]
De standaard afdrukbreedte is 80. Deze breedte kan worden aangepast met behulp van een afdrukbreedte in de opmaakaanduiding. Bijvoorbeeld:
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) |]
Produceert
[|(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)|]
Als u een afdrukbreedte van 0 opgeeft, wordt er geen afdrukbreedte gebruikt. Eén regel tekst resulteert, behalve wanneer ingesloten tekenreeksen in de uitvoer regeleinden bevatten. Bijvoorbeeld
printfn "%0A" [| for i in 1 .. 5 -> (i, i*i) |]
printfn "%0A" [| for i in 1 .. 5 -> "abc\ndef" |]
Produceert
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]
[|"abc
def"; "abc
def"; "abc
def"; "abc
def"; "abc
def"|]
Een dieptelimiet van 4 wordt gebruikt voor reekswaarden (IEnumerable
) die worden weergegeven als seq { ...}
. Er wordt een dieptelimiet van 100 gebruikt voor lijst- en matrixwaarden.
Bijvoorbeeld:
printfn "%A" (seq { for i in 1 .. 10 -> (i, i*i) })
Produceert
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]
Blok inspringing wordt ook gebruikt voor de structuur van openbare records en samenvoegwaarden. Bijvoorbeeld:
type R = { X : int list; Y : string list }
printfn "%A" { X = [ 1;2;3 ]; Y = ["one"; "two"; "three"] }
Produceert
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Als %+A
deze wordt gebruikt, wordt de privéstructuur van records en samenvoegingen ook onthuld met behulp van reflectie. Bijvoorbeeld
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
Produceert
external view:
R
internal view:
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Grote, cyclische of diep geneste waarden
Grote gestructureerde waarden worden opgemaakt tot een maximaal totaal aantal objectknooppunten van 10000.
Diep geneste waarden worden opgemaakt tot een diepte van 100. In beide gevallen ...
wordt gebruikt om een deel van de uitvoer te verwijderen. Bijvoorbeeld:
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)
produceert een grote uitvoer met enkele onderdelen:
Node(Tip, Node(Tip, ....Node (..., ...)...))
Cycli worden gedetecteerd in de objectgrafieken en ...
worden gebruikt op plaatsen waar cycli worden gedetecteerd. Bijvoorbeeld
type R = { mutable Links: R list }
let r = { Links = [] }
r.Links <- [r]
printfn "%A" r
Produceert
{ Links = [...] }
Luie, null- en functiewaarden
Luie waarden worden afgedrukt als Value is not created
of gelijkwaardige tekst wanneer de waarde nog niet is geëvalueerd.
Null-waarden worden afgedrukt als null
het statische type van de waarde wordt bepaald als een samenvoegingstype waarbij null
een toegestane weergave is.
F#-functiewaarden worden bijvoorbeeld afgedrukt als de intern gegenereerde sluitingsnaam <fun:it@43-7>
.
Opmaak van tekst zonder opmaak aanpassen met StructuredFormatDisplay
Wanneer u de %A
aanduiding gebruikt, wordt de aanwezigheid van het StructuredFormatDisplay
kenmerk voor typedeclaraties gerespecteerd. Dit kan worden gebruikt om surrogaattekst en -eigenschap op te geven om een waarde weer te geven. Voorbeeld:
[<StructuredFormatDisplay("Counts({Clicks})")>]
type Counts = { Clicks:int list}
printfn "%20A" {Clicks=[0..20]}
Produceert
Counts([0; 1; 2; 3;
4; 5; 6; 7;
8; 9; 10; 11;
12; 13; 14;
15; 16; 17;
18; 19; 20])
Opmaak van tekst zonder opmaak aanpassen door te overschrijven ToString
De standaard implementatie van ToString
is waarneembaar in F#-programmering. Vaak zijn de standaardresultaten niet geschikt voor gebruik in de programmeurgerichte informatieweergave of gebruikersuitvoer. Als gevolg hiervan is het gebruikelijk om de standaard implementatie te overschrijven.
Standaard overschrijven F#-record- en samenvoegtypen de implementatie met ToString
een implementatie die wordt gebruikt sprintf "%+A"
. Bijvoorbeeld:
type Counts = { Clicks:int list }
printfn "%s" ({Clicks=[0..10]}.ToString())
Produceert
{ Clicks = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] }
Voor klassetypen is er geen standaard implementatie ToString
van opgegeven en wordt de standaard .NET-standaard gebruikt, waarmee de naam van het type wordt gerapporteerd. Bijvoorbeeld:
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())
Produceert
Default structured print gives this:
[MyClassType; MyClassType]
Default ToString gives:
[MyClassType; MyClassType]
Het toevoegen van een onderdrukking voor ToString
kan een betere opmaak geven.
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())
Produceert
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])]
Opmaak van tekst zonder opmaak aanpassen met StructuredFormatDisplay
en ToString
Als u consistente opmaak voor %A
en %O
opmaakaanduidingen wilt bereiken, combineert u het gebruik van StructuredFormatDisplay
met een onderdrukking van ToString
. Bijvoorbeeld:
[<StructuredFormatDisplay("{DisplayText}")>]
type MyRecord =
{
a: int
}
member this.DisplayText = this.ToString()
override _.ToString() = "Custom ToString"
De volgende definities evalueren
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]}"
geeft de tekst
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]"
Het gebruik van StructuredFormatDisplay
met de ondersteunende DisplayText
eigenschap betekent dat het feit dat het myRec
een structureel recordtype is genegeerd tijdens gestructureerd afdrukken en dat de onderdrukking in ToString()
alle omstandigheden de voorkeur heeft.
Een implementatie van de System.IFormattable
interface kan worden toegevoegd voor verdere aanpassing in aanwezigheid van specificaties voor .NET-indeling.
F# Interactief gestructureerd afdrukken
F# Interactive (dotnet fsi
) maakt gebruik van een uitgebreide versie van gestructureerde tekstopmaak zonder opmaak om waarden te rapporteren en biedt aanvullende aanpassingsmogelijkheden. Zie F# Interactive voor meer informatie.
Weergaven voor foutopsporing aanpassen
Foutopsporingsprogramma's voor .NET respecteren het gebruik van kenmerken zoals DebuggerDisplay
en DebuggerTypeProxy
, en deze hebben invloed op de gestructureerde weergave van objecten in foutopsporingsprogramma-inspectievensters.
De F#-compiler heeft deze kenmerken automatisch gegenereerd voor gediscrimineerde samenvoeg- en recordtypen, maar niet voor klasse-, interface- of structtypen.
Deze kenmerken worden genegeerd in F#-opmaak voor tekst zonder opmaak, maar het kan handig zijn om deze methoden te implementeren om weergaven te verbeteren bij het opsporen van fouten in F#-typen.