共用方式為


純文字格式設定

F# 支援使用 printfprintfnsprintf和相關函式來檢查純文字的類型檢查格式。 例如,

dotnet fsi

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

提供輸出

Hello world, 2 + 2 is 4

F# 也允許結構化值格式化為純文字。 例如,請考慮下列範例,將輸出格式化為類似矩陣的 Tuple 顯示。

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)]]

當您在格式化字串中使用%Aprintf格式時,會啟動結構化純文字格式設定。 當格式化 F# 互動式中的值輸出時,也會啟動它,其中輸出包含額外的資訊,而且可另外自定義。 純文本格式設定也可以透過 F# 等位和記錄值的任何呼叫 x.ToString() 來觀察,包括偵錯、記錄和其他工具中隱含發生的呼叫。

檢查 printf格式字串

如果 printf 格式函式與格式字串中的 printf 格式規範不符的自變數搭配使用,將會報告編譯時期錯誤。 例如,

sprintf "Hello %s" (2+2)

提供輸出

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

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

從技術上講,使用 printf 和其他相關函式時,F# 編譯程式中的特殊規則會檢查傳遞為格式字串的字串常值,確保套用的後續自變數是正確的類型,以符合所使用的格式規範。

的格式規範 printf

格式的格式規格 printf 是具有 % 指出格式之標記的字串。 格式佔位元是由類型解譯的位置所組成 %[flags][width][.precision][type] ,如下所示:

格式規範 Type(s) 備註
%b boolSystem.Boolean 格式化為 truefalse
%s stringSystem.String 格式化為其未逸出的內容
%c charSystem.Char 格式化為字元常值
%d%i 基本整數類型 格式化為十進位整數,如果基本整數類型帶正負號,則為帶正負號
%u 基本整數類型 格式化為不帶正負號的十進位整數
%x%X 基本整數類型 格式化為不帶正負號的十六進位數位(分別十六進位數位的 a-f 或 A-F)
%o 基本整數類型 格式化為不帶正負號的八進位數位
%B 基本整數類型 格式化為無符號二進位數
%e%E 基本浮點類型 格式化為帶正負號的值, [-]d.dddde[sign]ddd 其中 d 為單一十進位數,dddd 是一或多個十進位數,ddd 正好是三個十進制數,而符號為 +-
%f%F 基本浮點類型 格式化為具有 格式 [-]dddd.dddd的帶正負號值,其中 dddd 是一或多個十進制數。 小數點之前的位數取決於數位的大小,小數點後面的位數取決於所要求的有效位數。
%g%G 基本浮點類型 使用 格式化為列印 %f%e 格式的帶正負號值,無論哪個值和精確度都比較精簡。
%M a decimalSystem.Decimal) 值 使用 "G" 的格式規範格式化 System.Decimal.ToString(format)
%O 任何值 格式化物件並呼叫其 System.Object.ToString() 方法
%A 任何值 使用 結構化純文字格式 設定與預設版面配置設定格式化
%a 任何值 需要兩個自變數:接受內容參數和值的格式化函式,以及要列印的特定值
%t 任何值 需要一個自變數:接受可輸出或傳回適當文字之內容參數的格式函式
%% (無) 不需要任何自變數,並列印純百分比符號: %

基本整數類型為byteSystem.Byte)、()、 int16sbyteSystem.Int16System.SByte)、 uint16System.UInt32uint32System.Int64System.Int32int64System.UInt16int32()、 uint64 () nativeintunativeintSystem.UInt64System.IntPtr()。System.UIntPtr 基本浮點類型為 floatSystem.Double)、 float32System.Single) 和 decimalSystem.Decimal)。

選擇性寬度是整數,表示結果的最小寬度。 例如, %6d 列印整數,前面加上空格以填滿至少六個字元。 如果 width 是 *,則會採用額外的整數自變數來指定對應的寬度。

有效的旗標為:

旗標 影響
0 新增零而不是空格,以構成所需的寬度
- 左對齊指定寬度內的結果
+ +如果數位為正數,請新增字元(以符合-負號)
空白字元 如果數位為正數,請新增額外的空格(以符合負號的 '-' 正負號)

printf # 旗標無效,如果使用編譯時間錯誤,則會報告錯誤。

值會使用不因文化特性而異來格式化。 文化特性設定與printf格式化無關,除非它們會影響和%A格式設定的結果%O。 如需詳細資訊,請參閱 結構化純文本格式設定。

%A 格式

%A格式規範是用來以人類可讀取的方式格式化值,也可用於報告診斷資訊。

基本值

使用 %A 規範格式化純文本時,F# 數值會以其後綴和不因文化特性而格式化。 浮點值會使用10個浮點精確度的位置來格式化。 例如,

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

生產

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

使用 %A 規範時,字串會使用引號來格式化。 逸出碼不會新增,而是列印原始字元。 例如,

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

生產

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

.NET 值

使用%A規範格式化純文字時,非 F# .NET 物件會使用 x.ToString()System.Globalization.CultureInfo.CurrentUICulture所提供的 System.Globalization.CultureInfo.CurrentCulture .NET 預設設定來格式化。 例如,

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

生產

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

結構化值

使用 %A 規範格式化純文字時,區塊縮排會用於 F# 清單和元組。 如先前的範例所示。 也會使用數位結構,包括多維度陣列。 單一維度陣列會以 [| ... |] 語法顯示。 例如,

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

生產

[|(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)|]

默認列印寬度為80。 此寬度可以使用格式規範中的列印寬度來自定義。 例如,

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) |]

生產

[|(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)|]

指定 0 的列印寬度會導致不使用列印寬度。 除了輸出中的內嵌字串包含換行符之外,單行文字將會產生。 例如:

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

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

生產

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

深度限制為 4 用於序列 (IEnumerable) 值,其顯示為 seq { ...}。 清單和陣列值會使用100的深度限制。 例如,

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

生產

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

區塊縮排也用於公用記錄和等位值的結構。 例如,

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

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

生產

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

如果使用 %+A ,則也會使用反映來顯示記錄和等位的私人結構。 例如:

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

生產

external view:
R

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

大型、迴圈或深層巢狀值

大型結構化值會格式化為最大整體物件節點計數 10000。 深度巢狀值會格式化為100的深度。 在這兩種情況下, ... 都用來將部分輸出滑倒。 例如,

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)

會產生具有某些部分的較大輸出:

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

迴圈會在物件圖形中偵測到,並 ... 用於偵測到迴圈的位置。 例如:

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

生產

{ Links = [...] }

延遲、Null 和函式值

當尚未評估值時,延遲值會列印為 Value is not created 或對等的文字。

Null 值會列印為 null ,除非值的靜態類型決定為等位型別,其中 null 是允許的表示法。

F# 函式值會列印為其內部產生的關閉名稱,例如 <fun:it@43-7>

使用 自訂純文字格式設定 StructuredFormatDisplay

使用 %A 規範時,會遵守類型宣告上屬性的存在 StructuredFormatDisplay 。 這可用來指定 Surrogate 文字和屬性來顯示值。 例如:

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

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

生產

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

覆寫以自定義純文本格式設定 ToString

的預設實 ToString 作可在 F# 程式設計中觀察到。 默認結果通常不適合用於程式設計人員面向信息顯示或用戶輸出,因此通常會覆寫預設實作。

根據預設,F# 記錄和等位型別會使用 的實作覆寫 的 ToStringsprintf "%+A"作。 例如,

type Counts = { Clicks:int list }

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

生產

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

針對類別類型,不會提供 預設的 ToString 實作,而且會使用 .NET 預設值來報告型別的名稱。 例如,

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())

生產

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

為新增覆寫 ToString 可提供更佳的格式設定。

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())

生產

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])]

使用 StructuredFormatDisplay 和自訂純文字格式設定 ToString

若要達到 和 %O 格式規範的一致格式%A設定,請將 的用法StructuredFormatDisplay與的ToString覆寫結合。 例如,

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

    override _.ToString() = "Custom ToString"

評估下列定義

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]}"

提供文字

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]"

搭配支援屬性使用 StructuredFormatDisplay 表示在結構化列印期間會忽略 結構記錄類型,myRec而且在所有情況下都偏好覆寫 ToString()DisplayText

您可以新增 介面的 System.IFormattable 實作,以在 .NET 格式規格存在的情況下進一步自定義。

F# 互動式結構化列印

F# Interactive (dotnet fsi) 使用結構化純文字格式的擴充版本來報告值,並允許額外的自定義性。 如需詳細資訊,請參閱 F# Interactive

自定義偵錯顯示

.NET 的調試程式會遵守 和 等DebuggerDisplayDebuggerTypeProxy屬性的使用,這些會影響調試程式檢查視窗中對象的結構化顯示。 F# 編譯程式會自動為受歧視的等位和記錄類型產生這些屬性,但不是類別、介面或結構類型。

這些屬性在 F# 純文字格式設定中會被忽略,但是實作這些方法有助於改善偵錯 F# 類型時的顯示。

另請參閱