Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
F# unterstützt die typgecheckte Formatierung von Nur-Text mithilfe printfvon , printfn, sprintfund verwandten Funktionen.
Beispiel:
dotnet fsi
> printfn "Hello %s, %d + %d is %d" "world" 2 2 (2+2);;
gibt die Ausgabe an
Hello world, 2 + 2 is 4
F# ermöglicht auch die Formatierung strukturierter Werte als Nur-Text. Betrachten Sie beispielsweise das folgende Beispiel, das die Ausgabe als matrixähnliche Anzeige von Tupeln formatiert.
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)]]
Strukturierte Nur-Text-Formatierung wird aktiviert, wenn Sie das %A Format in printf Formatierungszeichenfolgen verwenden.
Es wird auch aktiviert, wenn die Ausgabe von Werten in F# interaktiv formatiert wird, wobei die Ausgabe zusätzliche Informationen enthält und zusätzlich anpassbar ist.
Die Nur-Text-Formatierung kann auch durch aufrufe von x.ToString() F#-Union- und Datensatzwerten beobachtet werden, einschließlich derJenigen, die implizit beim Debuggen, Protokollieren und anderen Tools auftreten.
Überprüfen von printf-format-Zeichenfolgen
Ein Kompilierungsfehler wird gemeldet, wenn eine printf Formatierungsfunktion mit einem Argument verwendet wird, das nicht mit den Druckformatbezeichnern in der Formatzeichenfolge übereinstimmt. Beispiel:
sprintf "Hello %s" (2+2)
gibt die Ausgabe an
sprintf "Hello %s" (2+2)
----------------------^
stdin(3,25): error FS0001: The type 'string' does not match the type 'int'
Technisch gesehen überprüft eine spezielle Regel im F#-Compiler die als Formatzeichenfolge übergebene Zeichenfolgenliteral und stellt sicher, printf dass die nachfolgenden Angewendeten Argumente vom richtigen Typ sind, um den verwendeten Formatbezeichnern zu entsprechen.
Formatbezeichner für printf
Formatspezifikationen für printf Formate sind Zeichenfolgen mit % Markierungen, die das Format angeben. Formatplatzhalter bestehen darin %[flags][width][.precision][type] , wo der Typ wie folgt interpretiert wird:
| Formatbezeichner | Typ(en) | Bemerkungen |
|---|---|---|
%b |
bool (System.Boolean) |
Formatiert als true oder false |
%s |
string (System.String) |
Formatiert als nicht dargestellter Inhalt |
%c |
char (System.Char) |
Als Zeichenliteral formatiert |
%d, %i |
einen einfachen ganzzahligen Typ | Formatiert als dezimale ganze Zahl, signiert, wenn der einfache ganzzahlige Typ signiert ist |
%u |
einen einfachen ganzzahligen Typ | Formatiert als nicht signierte ganzzahlige Dezimalzahl |
%x, %X |
einen einfachen ganzzahligen Typ | Formatiert als nicht signierte Hexadezimalzahl (a-f oder A-F für Hexadezimalstellen) |
%o |
einen einfachen ganzzahligen Typ | Formatiert als nicht signierte oktale Zahl |
%B |
einen einfachen ganzzahligen Typ | Als nicht signierte Binärzahl formatiert |
%e, %E |
einen einfachen Gleitkommatyp | Formatiert als signierter Wert mit dem Formular [-]d.dddde[sign]ddd , in dem d eine einzelne Dezimalziffer ist, dddd ist eine oder mehrere Dezimalziffern, ddd ist genau drei Dezimalziffern, und das Vorzeichen ist + oder - |
%f, %F |
einen einfachen Gleitkommatyp | Formatiert als signierter Wert mit dem Formular [-]dddd.dddd, wobei dddd eine oder mehrere Dezimalziffern vorhanden sind. Die Anzahl der Ziffern vor dem Dezimalkomma hängt von der Größe der Zahl ab, und die Anzahl der Ziffern nach dem Dezimalkomma hängt von der angeforderten Genauigkeit ab. |
%g, %G |
einen einfachen Gleitkommatyp | Formatiert als signierter Wert, der in %f oder %e im Format gedruckt wird, je nachdem, welcher Wert für den angegebenen Wert und die Genauigkeit kompakter ist. |
%M |
a decimal (System.Decimal) value |
Formatiert mit dem "G" Formatbezeichner für System.Decimal.ToString(format) |
%O |
beliebiger Wert | Formatiert durch Boxen des Objekts und Aufrufen der System.Object.ToString() Methode |
%A |
beliebiger Wert | Formatiert mit strukturierter Nur-Text-Formatierung mit den Standardlayouteinstellungen |
%a |
beliebiger Wert | Erfordert zwei Argumente: eine Formatierungsfunktion, die einen Kontextparameter und den Wert akzeptiert, und den zu druckenden Wert |
%t |
beliebiger Wert | Erfordert ein Argument: Eine Formatierungsfunktion akzeptiert einen Kontextparameter, der entweder ausgibt oder den entsprechenden Text zurückgibt. |
%% |
(kein) | Erfordert keine Argumente und druckt ein einfaches Prozentzeichen: % |
Grundlegende ganzzahlige Typen sind byte (), (), sbyte (System.SByteSystem.Byte), int16System.Int16(), uint16 (System.UInt16), int32 (System.Int32), uint32 (), int64 (System.UInt32), (System.Int64), nativeintuint64 (System.IntPtrSystem.UInt64) und unativeint ().System.UIntPtr
Grundlegende Gleitkommatypen sind float (), float32 (System.DoubleSystem.Single) und decimal (System.Decimal).
Die optionale Breite ist eine ganze Zahl, die die minimale Breite des Ergebnisses angibt. Druckt z. B %6d . eine ganzzahlige Zahl mit Leerzeichen, um mindestens sechs Zeichen zu füllen. Wenn die Breite lautet *, wird ein zusätzliches ganzzahliges Argument verwendet, um die entsprechende Breite anzugeben.
Gültige Kennzeichen sind:
| Flagge | Effekt |
|---|---|
0 |
Fügen Sie Nullen anstelle von Leerzeichen hinzu, um die erforderliche Breite zu bilden. |
- |
Linksbündig ausrichten des Ergebnisses innerhalb der angegebenen Breite |
+ |
Add a + character if the number is positive (to match a - sign for negatives) |
| Leerzeichen | Fügen Sie ein zusätzliches Leerzeichen hinzu, wenn die Zahl positiv ist (um einem "-"-Zeichen für Negative zu entsprechen) |
Das Printf-Flag # ist ungültig, und ein Kompilierungszeitfehler wird gemeldet, wenn es verwendet wird.
Werte werden mit invarianter Kultur formatiert. Kultureinstellungen sind für die Formatierung irrelevant printf , es sei denn, sie wirken sich auf die Ergebnisse %O und %A Formatierungen aus. Weitere Informationen finden Sie unter strukturierte Nur-Text-Formatierung.
%A Formatierung
Der %A Formatbezeichner wird verwendet, um Werte auf lesbare Weise zu formatieren und kann auch zum Melden von Diagnoseinformationen hilfreich sein.
Grundtypenwerte
Beim Formatieren von Nur-Text mithilfe des %A Bezeichners werden numerische F#-Werte mit ihrem Suffix und der invarianten Kultur formatiert. Gleitkommawerte werden mit 10 Gleitkommagenauigkeitspunkten formatiert. Beispiel:
printfn "%A" (1L, 3n, 5u, 7, 4.03f, 5.000000001, 5.0000000001)
Produziert
(1L, 3n, 5u, 7, 4.03000021f, 5.000000001, 5.0)
Bei Verwendung des %A Bezeichners werden Zeichenfolgen mit Anführungszeichen formatiert. Escapecodes werden nicht hinzugefügt, und stattdessen werden die unformatierten Zeichen gedruckt. Beispiel:
printfn "%A" ("abc", "a\tb\nc\"d")
Produziert
("abc", "a b
c"d")
.NET-Werte
Beim Formatieren von Nur-Text mithilfe des %A Bezeichners werden nicht-F#-.NET-Objekte mithilfe x.ToString() der Standardeinstellungen von .NET formatiert, die von System.Globalization.CultureInfo.CurrentCulture und System.Globalization.CultureInfo.CurrentUICulture. Beispiel:
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
Produziert
Culture 1: 31.12.1999 00:00:00
Culture 2: 12/31/1999 12:00:00 AM
Strukturierte Werte
Beim Formatieren von Nur-Text mithilfe des %A Bezeichners wird der Blockeinzug für F#-Listen und Tupel verwendet. Dies ist im vorherigen Beispiel dargestellt.
Die Struktur von Arrays wird auch verwendet, einschließlich mehrdimensionaler Arrays. Eindimensionale Arrays werden mit [| ... |] Syntax angezeigt. Beispiel:
printfn "%A" [| for i in 1 .. 20 -> (i, i*i) |]
Produziert
[|(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)|]
Die Standarddruckbreite beträgt 80. Diese Breite kann mithilfe einer Druckbreite im Formatbezeichner angepasst werden. Beispiel:
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) |]
Produziert
[|(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)|]
Wenn Sie eine Druckbreite von 0 angeben, wird keine Druckbreite verwendet. Eine einzelne Textzeile führt dazu, es sei denn, eingebettete Zeichenfolgen in der Ausgabe enthalten Zeilenumbrüche. Beispiel:
printfn "%0A" [| for i in 1 .. 5 -> (i, i*i) |]
printfn "%0A" [| for i in 1 .. 5 -> "abc\ndef" |]
Produziert
[|(1, 1); (2, 4); (3, 9); (4, 16); (5, 25)|]
[|"abc
def"; "abc
def"; "abc
def"; "abc
def"; "abc
def"|]
Ein Tiefengrenzwert von 4 wird für Sequenzwerte (IEnumerable) verwendet, die als seq { ...}angezeigt werden. Für Listen- und Arraywerte wird ein Tiefengrenzwert von 100 verwendet.
Beispiel:
printfn "%A" (seq { for i in 1 .. 10 -> (i, i*i) })
Produziert
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]
Blockeinzug wird auch für die Struktur von öffentlichen Datensätzen und Union-Werten verwendet. Beispiel:
type R = { X : int list; Y : string list }
printfn "%A" { X = [ 1;2;3 ]; Y = ["one"; "two"; "three"] }
Produziert
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Wenn %+A verwendet wird, wird auch die private Struktur von Datensätzen und Gewerkschaften durch Reflexion offenbart. Beispiel:
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
Produziert
external view:
R
internal view:
{ X = [1; 2; 3]
Y = ["one"; "two"; "three"] }
Große, zyklische oder tief geschachtelte Werte
Große strukturierte Werte werden auf eine maximale Gesamtanzahl von Objektknoten 10000 formatiert.
Tief geschachtelte Werte werden in einer Tiefe von 100 formatiert. In beiden Fällen ... wird verwendet, um einige der Ausgaben auszublenden. Beispiel:
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)
erzeugt eine große Ausgabe mit einigen Teilen elidiert:
Node(Tip, Node(Tip, ....Node (..., ...)...))
Zyklen werden in den Objektdiagrammen erkannt und ... an Orten verwendet, an denen Zyklen erkannt werden. Beispiel:
type R = { mutable Links: R list }
let r = { Links = [] }
r.Links <- [r]
printfn "%A" r
Produziert
{ Links = [...] }
Lazy-, Null- und Funktionswerte
Lazy-Werte werden als Value is not created oder gleichwertiger Text gedruckt, wenn der Wert noch nicht ausgewertet wurde.
Nullwerte werden gedruckt, null es sei denn, der statische Typ des Werts wird als Union-Typ bestimmt, bei dem null es sich um eine zulässige Darstellung handelt.
F#-Funktionswerte werden als intern generierter Schließname gedruckt, <fun:it@43-7>z. B. .
Anpassen der Formatierung von Nur-Text mit StructuredFormatDisplay
Bei Verwendung des %A Bezeichners wird das Vorhandensein des StructuredFormatDisplay Attributs für Typdeklarationen berücksichtigt. Dies kann verwendet werden, um Ersatztext und Eigenschaft anzugeben, um einen Wert anzuzeigen. Beispiel:
[<StructuredFormatDisplay("Counts({Clicks})")>]
type Counts = { Clicks:int list}
printfn "%20A" {Clicks=[0..20]}
Produziert
Counts([0; 1; 2; 3;
4; 5; 6; 7;
8; 9; 10; 11;
12; 13; 14;
15; 16; 17;
18; 19; 20])
Anpassen der Nur-Text-Formatierung durch Außerkraftsetzung ToString
Die Standardimplementierung ist in der ToString F#-Programmierung feststellbar. Häufig eignen sich die Standardergebnisse nicht für die Verwendung in der Anzeige von Programmerinformationen oder der Benutzerausgabe, und daher ist es üblich, die Standardimplementierung außer Kraft zu setzen.
Standardmäßig überschreiben F#-Datensatz- und Union-Typen die Implementierung ToString mit einer Implementierung, die verwendet sprintf "%+A"wird. Beispiel:
type Counts = { Clicks:int list }
printfn "%s" ({Clicks=[0..10]}.ToString())
Produziert
{ Clicks = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10] }
Für Klassentypen wird keine Standardimplementierung ToString bereitgestellt, und der .NET-Standardwert wird verwendet, der den Namen des Typs meldet. Beispiel:
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())
Produziert
Default structured print gives this:
[MyClassType; MyClassType]
Default ToString gives:
[MyClassType; MyClassType]
Durch das Hinzufügen einer Außerkraftsetzung ToString kann eine bessere Formatierung erzielt werden.
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())
Produziert
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])]
Anpassen der Nur-Text-Formatierung mit StructuredFormatDisplay und ToString
Um eine konsistente Formatierung für %A bezeichner und %O formatieren zu können, kombinieren Sie die Verwendung StructuredFormatDisplay mit einer Außerkraftsetzung von ToString. Beispiel:
[<StructuredFormatDisplay("{DisplayText}")>]
type MyRecord =
{
a: int
}
member this.DisplayText = this.ToString()
override _.ToString() = "Custom ToString"
Auswerten der folgenden Definitionen
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]}"
gibt den Text an
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]"
Die Verwendung mit StructuredFormatDisplay der unterstützenden DisplayText Eigenschaft bedeutet, dass der myRec strukturelle Datensatztyp beim strukturierten Drucken ignoriert wird und die Außerkraftsetzung in ToString() allen Fällen bevorzugt wird.
Eine Implementierung der System.IFormattable Schnittstelle kann für weitere Anpassungen in Anwesenheit von .NET-Formatspezifikationen hinzugefügt werden.
F# Interaktiver strukturierter Druck
F# Interactive (dotnet fsi) verwendet eine erweiterte Version der strukturierten Nur-Text-Formatierung, um Werte zu melden und eine zusätzliche Anpassbarkeit zu ermöglichen. Weitere Informationen finden Sie unter F# Interactive.
Anpassen von Debuganzeigen
Debugger für .NET respektieren die Verwendung von Attributen wie DebuggerDisplay und DebuggerTypeProxy, und diese wirken sich auf die strukturierte Anzeige von Objekten in Debugger-Inspektionsfenstern aus.
Der F#-Compiler generierte diese Attribute automatisch für diskriminierte Union- und Datensatztypen, jedoch nicht für Klassen-, Schnittstellen- oder Strukturtypen.
Diese Attribute werden in der F#-Nur-Text-Formatierung ignoriert, aber es kann hilfreich sein, diese Methoden zu implementieren, um die Anzeige beim Debuggen von F#-Typen zu verbessern.