18

次の F# コードでは、printfnが 3 回呼び出されることを期待します。それぞれ紐付き。ただし、最終行はコンパイルされません ( The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>')。

これが機能することを意味する最初の 2 行についてはどうでしょうか。それらも単なる文字列ではありませんか?

open System

printfn ("\r\n") // Works
printfn ("DANNY") // Works
printfn (DateTime.Now.ToLongTimeString()) // Doesn't compile
4

2 に答える 2

10

@Leeの答えは可能な回避策として正しいですが、コードで何が起こるかについては説明していません。

printf "foo"で、"foo"は書式設定する文字列ではありません。代わりに、それ自体が入力フォーマッタです。より具体的には、 の実際の型を推測するために使用される文字列リテラルTextWriterFormat<'T>です。

の署名printfは次のとおりです。

printf : TextWriterFormat<'T> -> 'T

printfn ("DANNY")には書式指定子が含まれていないため、F# コンパイラは a を推論し、TextWriterFormat<unit>式全体が になりprintfn ("DANNY") ()ます。

変数を使用すると、どの書式指定子が存在するかを静的に予測することは不可能です。メソッドがまたはToLongTimeString()の文字列を返すことができた場合、返される関数のプロトタイプは何でしょうか?"%s""%d %d %d"

正しい型を推測する場合、文字列リテラルは正常に機能しますが、変数またはletバインドは機能しません。

let foo1 = "foo"
let bar = printf foo // does not compile
[<Literal>] let foo2 = "foo";; // see update below
let bar = printf foo2 // compiles fine

いずれにせよ、常にフォーマット指定子を使用する方がはるかに安全に見えます:

printf "%s" "DANNY"
printf "%s" (DateTime.Now.ToLongTimeString())

更新: VS2013 で警告 FS0058を回避するために、値の;;後に二重コロンを入力することを忘れないでください。[<Literal>]

于 2013-08-31T23:25:42.383 に答える