在以下F#代码中; 我希望它printfn被召唤三次; 每个都有一个字符串.但是,底线不会编译(The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>').
什么是前两行意味着这可以工作?它们不仅仅是弦乐吗?
open System
printfn ("\r\n") // Works
printfn ("DANNY") // Works
printfn (DateTime.Now.ToLongTimeString()) // Doesn't compile
Run Code Online (Sandbox Code Playgroud)
Lee*_*Lee 19
F#编译器静态分析您传递给的格式字符串,printfn以检查您传递的参数是否对您使用的格式说明符有效.例如,以下内容无法编译:
printfn "%d" "some value"
Run Code Online (Sandbox Code Playgroud)
因为string与%d格式说明符不兼容.编译器将有效格式字符串转换为TextWriterFormat<T>.
它不能使用任意字符串执行此操作,并且由于它不执行转换,因此您将获得上面的类型错误.
您可以使用自己进行转换Printf.TextWriterFormat.例如,对于需要a string和a的格式字符串,int您可以使用:
let f = Printf.TextWriterFormat<string -> int -> unit>("The length of '%s' is: %d")
printfn f "something" 9
Run Code Online (Sandbox Code Playgroud)
由于您的字符串没有格式占位符,您可以执行以下操作:
let f = Printf.TextWriterFormat<unit>(DateTime.Now.ToLongTimeString())
printfn f
Run Code Online (Sandbox Code Playgroud)
根据可能的解决方法,@ Lee的答案是正确的,但它没有描述您的代码会发生什么.
在表达式中printf "foo","foo"不是要格式化的字符串.相反,它本身就是输入格式化程序.更具体地说,它是一个用于推断实际类型的字符串文字TextWriterFormat<'T>.
签名printf是:
printf : TextWriterFormat<'T> -> 'T
Run Code Online (Sandbox Code Playgroud)
由于printfn ("DANNY")不包含任何格式说明符,因此F#编译器推断出a TextWriterFormat<unit>,整个表达式变为printfn ("DANNY") ().
使用变量,不可能静态地预测那里的格式说明符.考虑一下ToLongTimeString()方法是否能够返回字符串"%s"或者"%d %d %d"返回函数的原型是什么?
在推断出正确的类型时,字符串文字可以正常工作,但变量或let-binding不起作用:
let foo1 = "foo"
let bar = printf foo // does not compile
[<Literal>] let foo2 = "foo";; // see update below
let bar = printf foo2 // compiles fine
Run Code Online (Sandbox Code Playgroud)
无论如何,总是使用格式说明符看起来更安全:
printf "%s" "DANNY"
printf "%s" (DateTime.Now.ToLongTimeString())
Run Code Online (Sandbox Code Playgroud)
更新:不要忘记;;在[<Literal>]值后键入双冒号以避免在VS2013中警告 FS0058.
| 归档时间: |
|
| 查看次数: |
3507 次 |
| 最近记录: |