次の方法で共有


プレーン テキストの書式設定

F# では、 printfprintfnsprintf、および関連する関数を使用したプレーン テキストの型チェック形式がサポートされています。 たとえば、

dotnet fsi

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

は出力を提供します

Hello world, 2 + 2 is 4

F# では、構造化された値をプレーン テキストとして書式設定することもできます。 たとえば、出力をタプルのマトリックスのような表示として書式設定する次の例を考えてみましょう。

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

構造化プレーンテキストの書式設定は、書式設定文字列で %A 形式を使用すると printf アクティブになります。 また、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] で構成されます。

書式指定子 タイプ 注釈
%b bool (System.Boolean) trueまたはfalse
%s string (System.String) エスケープされていないコンテンツとして書式設定
%c char (System.Char) 文字リテラルとして書式設定される
%d%i 基本的な整数型 10 進整数として書式設定され、基本整数型が符号付きの場合は符号が付けられます。
%u 基本的な整数型 符号なし 10 進整数として書式設定
%x%X 基本的な整数型 符号なし 16 進数 (それぞれ 16 進数の場合は a から f または A から F) として書式設定されます。
%o 基本的な整数型 符号なし 8 進数として書式設定
%B 基本的な整数型 符号なし 2 進数として書式設定
%e%E 基本的な浮動小数点型 d が 1 桁の [-]d.dddde[sign]ddd 10 進数、dddd が 1 桁以上、ddd が正確に 3 桁の 10 進数、符号が + または -
%f%F 基本的な浮動小数点型 ddddは 1 桁以上の 10 進数で、[-]dddd.ddddフォームを持つ符号付き値として書式設定されます。 小数点の前の桁数は数値の大きさに依存し、小数点の後の桁数は要求された有効桁数によって異なります。
%g%G 基本的な浮動小数点型 %f形式または%e形式で印刷される符号付き値として使用して書式設定されます。指定された値と有効桁数に対して、どちらか小さくなっています。
%M decimal (System.Decimal) 値 "G" 書式指定子を使用して書式設定 System.Decimal.ToString(format)
%O 任意の値 オブジェクトをボックス化し、その System.Object.ToString() メソッドを呼び出すことによって書式設定されます
%A 任意の値 既定のレイアウト設定で 構造化されたプレーンテキスト書式を 使用して書式設定する
%a 任意の値 2 つの引数が必要です。コンテキスト パラメーターと値を受け取る書式設定関数と、出力する特定の値
%t 任意の値 1 つの引数が必要です。適切なテキストを出力または返すコンテキスト パラメーターを受け取る書式設定関数
%% (なし) 引数を必要とせず、単純なパーセント記号を出力します。 %

基本的な整数型は、 byte (System.Byte)、 sbyte (System.SByte)、 int16 (System.Int16)、 uint16 (System.UInt16)、 int32 (System.Int32)、 uint32 (System.UInt32)、 int64 (System.Int64)、 uint64 (System.UInt64)、 nativeint (System.IntPtr)、および unativeint (System.UIntPtr) です。 基本的な浮動小数点型は、 float (System.Double)、 float32 (System.Single)、および decimal (System.Decimal) です。

省略可能な幅は、結果の最小幅を示す整数です。 たとえば、 %6d は整数を出力し、少なくとも 6 文字を埋めるスペースを先頭に付けます。 width が *の場合は、対応する幅を指定するために余分な整数引数が使用されます。

有効なフラグは次のとおりです。

フラグ 影響
0 スペースの代わりにゼロを追加して、必要な幅を構成する
- 指定した幅内の結果を左揃えにする
+ 数値が正の場合は + 文字を追加します (負の符号の - に一致するため)
空白文字 数値が正の場合は余分なスペースを追加します (負の値の '-' 記号と一致するため)

printf # フラグが無効であり、使用されている場合はコンパイル時エラーが報告されます。

値はインバリアント カルチャを使用して書式設定されます。 カルチャ設定は、%O%Aの書式設定の結果に影響を与える場合を除き、printf書式設定とは無関係です。 詳細については、 構造化されたプレーンテキストの書式設定に関するページを参照してください。

%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 オブジェクトは、System.Globalization.CultureInfo.CurrentCultureSystem.Globalization.CultureInfo.CurrentUICultureによって指定された .NET の既定の設定を使用してx.ToString()を使用して書式設定されます。 たとえば、

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# リストとタプルにブロック インデントが使用されます。 上記の例を参照してください。 多次元配列を含む配列の構造も使用されます。 1 次元配列は、 [| ... |] 構文と共に表示されます。 たとえば、

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 に指定すると、印刷幅は使用されません。 出力内の埋め込み文字列に改行が含まれている場合を除き、1 行のテキストが生成されます。 次に例を示します。

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属性が存在することが考慮されます。 これは、サロゲート テキストとプロパティを指定して値を表示するために使用できます。 例えば次が挙げられます。

[<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# レコード型と共用体型は、sprintf "%+A"を使用する実装でToStringの実装をオーバーライドします。 たとえば、

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

%Aおよび%O書式指定子の一貫性のある書式設定を実現するには、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]"

サポートDisplayTextプロパティでStructuredFormatDisplayを使用することは、構造化された印刷中にmyRecが構造レコードの種類であるという事実が無視されることを意味し、ToString()のオーバーライドはすべての状況で優先されます。

System.IFormattable インターフェイスの実装を追加して、.NET 形式の仕様がある場合にさらにカスタマイズすることができます。

F# 対話型構造化印刷

F# Interactive (dotnet fsi) は、構造化されたプレーン テキスト形式の拡張バージョンを使用して値をレポートし、追加のカスタマイズを可能にします。 詳細については、「 F# Interactive」を参照してください。

デバッグ表示をカスタマイズする

.NET のデバッガーでは、 DebuggerDisplayDebuggerTypeProxyなどの属性の使用が考慮され、デバッガー検査ウィンドウでのオブジェクトの構造化された表示に影響します。 F# コンパイラは、判別共用体型とレコード型に対してこれらの属性を自動的に生成しましたが、クラス、インターフェイス、構造体型は生成しません。

これらの属性は、F# プレーン テキストの書式設定では無視されますが、F# 型をデバッグするときに表示を向上させるために、これらのメソッドを実装すると便利な場合があります。

こちらも参照ください