繁体   English   中英

为什么F#的printfn使用文字字符串,而不是字符串类型的值?

[英]Why does F#'s printfn work with literal strings, but not values of type string?

在以下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

F#编译器静态分析您传递给printfn的格式字符串,以检查您传递的参数是否对您使用的格式说明符有效。 例如,以下内容无法编译:

printfn "%d" "some value"

因为string与%d格式说明符不兼容。 编译器将有效的格式字符串转换为TextWriterFormat<T>

它不能使用任意字符串执行此操作,并且由于它不执行转换,因此您将获得上面的类型错误。

您可以使用Printf.TextWriterFormat进行转换。 例如,对于需要stringint的格式string ,您可以使用:

let f = Printf.TextWriterFormat<string -> int -> unit>("The length of '%s' is: %d")
printfn f "something" 9

由于您的字符串没有格式占位符,您可以执行以下操作:

let f = Printf.TextWriterFormat<unit>(DateTime.Now.ToLongTimeString())
printfn f

根据可能的解决方法,@ Lee的答案是正确的,但它没有描述您的代码会发生什么。

在表达式printf "foo""foo"不是要格式化的字符串。 相反,它本身就是输入格式化程序 更具体地说,它是一个字符串文字,用于推断TextWriterFormat<'T>的实际类型。

printf的签名是:

printf : TextWriterFormat<'T> -> 'T

由于printfn ("DANNY")不包含任何格式说明符,因此F#编译器推断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

无论如何,总是使用格式说明符看起来更安全:

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

更新 :不要忘记输入双冒号;; [<Literal>]以避免在VS2013中警告 FS0058。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM